Skip to main content

Full text of "Atari ST Introduction to MIDI Programming"

See other formats


Introduction to MIDI Programming 


Explore the infinite electronic 
musical capabilities of the ST 




































































k 

V 







Introduction to 
MIDI Programming 


MIDI Synthesizer 

U 1 — 1 — 1 1 — 1 - 1 1 g 

o Q D 

0 

Jo 

af 




By Len Dorfman and Dennis Young 

* l Iwnnixia r r - 

Abacus ■ma Software 






























































































First Printing, Aug.1986 
Printed in U.S.A. 

Copyright © 1986 Len Dorfman & Dennis Young 

Copyright © 1986 Abacus Software, Inc. 

P.O. Box 7219 
Grand Rapids, MI 49510 

This book is copyrighted. No part of this book may be reproduced, stored 
in a retrieval system, or transmitted in any form or by any means, 
electronic, mechanical, photocopying, recording or otherwise without the 
prior written permission of Abacus Software. 

Every effort has been made to insure complete and accurate information 
concerning the material presented in this book. However, Abacus Software 
can neither guarantee nor be held legally responsible for any mistakes in 
printing or faulty instructions contained in this book. The authors appreciate 
receiving notice of subsequent mistakes. 

ATARI, 520ST, ST, TOS, ST BASIC and ST LOGO are trademarks or 
registered trademarks of Atari Corp. 

GEM, GEM Draw and GEM Write are trademarks or registered trademarks 
of Digital Research Inc. 

CASIO CZ-101, CZ-1000 are registered trademarks of CASIO. 


ISBN 


0 - 916439 - 77-1 


Dedication 


This book is dedicated to Barbara & Rachel Dorfman and Carol, Josh & 
Katy Young. This stalwart group has stuck by our sides during periods of 
intensely hard and chaotic work. We could not have completed this work 
without their patience, love and support. Thank you. 

And to Michael and Linda Barnes, who believed. 











Table of Contents 

Preface i 

Chapter I MIDI and your ST 1 

1.1 Our Introduction to MIDI Programming 7 

1.2 What is MIDI? 8 

1.3 The Atari ST Hardware Hook-up 10 

1.4 Serial Transmission 12 

1.5 Qualities of MIDI SPECIFICATION 1.0 13 

1.6 Programming your Synthesizer 20 

1.7 A Guide For Buying your Synthesizer 22 

1.8 A Guide for Buying your MIDI Software 26 

1.9 Chapter 1 Summary 28 

Chapter II The MIDI LANGUAGE 29 

2.1 BITS & BYTES 31 

2.2 Data Format 36 

Chapter El Programming your Atari ST 51 

3.1 Hexadecimal Notation 53 

3.2 The Extended BIOS 56 

3.3 scaler. c source code 59 

3.4 readkey. c source code 66 

3.5 patch. c source code 77 

Chapter IV ST MUSIC BOX AUTO-PLAYER 93 

4.1 In the Beginning 95 

4.2 eio. c source code 101 

4.3 mdrive . c source code 119 

4.4 sets . c source code 145 

4.5 btdata. c source code 168 

4.6 interf. c source code 193 

4.7 movel. c source code 233 


Appendices 

251 

Compiling the programs 

253 

Optional diskette notes 

254 

Index 

255 


Abacus Software 


Atari ST MIDI Book 


Preface 

The Atari ST is a powerful computer line allowing both the creative 
programmer and the musically inclined a multitude of opportunities. One of 
the many fascinating features of the ST's architecture is the built-in MIDI 
interface and the MIDI INPUT AND MIDI OUTPUT ports on the back of 
the computer. The MIDI phenomenon is spreading like wildfire through the 
music community. This book is intended to explain what the MIDI 
experience is, and how the reader may use the ST to access these MIDI 
ports to communicate with commercially available synthesizers. 

In this book we have decided to publish our source code to the 
AUTO-MUSIC player for XLent Software's ST MUSIC BOX. Publishing 
a segment of our commercial source code feels a tad like improperly 
exposing ourselves. One positive aspect of this act is that the ST MUSIC 
BOX'S file format will now be open to public inspection. It is our hope that 
this will encourage other MIDI software developers to write file conversion 
code from other editors to our AUTO-PLAYER (presented in this book) and 
to use the file output from ST MUSIC BOX'S editor for other players. 
Both XLent Software, and we as programmers, have always believed that 
programs with open architecture are good for all members of the computer 
community. This book represents proof of our commitment. Also, this 
book is our way of saying "thank you" to all the programmers who have 
helped us learn about the development of commercial programs. It is our 
hope that this book may serve as one guidepost in others' quests to expand 
as programming artists. 

The source code is written in the 'C' programming language and we used 
the Alcyon version of 'C' which came with the Atari developer's kit. We 
believe programmers facile with any language will find use in perusing the 
code. 

We have also made the conscious decision to let the reader into the mind and 
heart of our programming team. By that we mean, this book is not just a 
book on MIDI synthesizers and the Atari ST. It is also a book which gives 
a bird's eye view into the lives of independent programmers. It is a book 
replete with the trials and tribulations of working to build a commercial 
program in 'C', more than a few instructive routines for the beginning 'C' 
programmer, and a quick start in MIDI-land for the experienced 
programmer. 



Abacus Software 


Atari ST MIDI Book 


One other note: many operations in the 'C programming language can be 
coded in very few lines. We, by choice, do not write source code so it will 
use the fewest lines or characters. Rather, our code is constructed so we 
will be able to quickly understand it months or years after not looking at it 
and modify it at will. So, if you are an experienced 'C hacker, feel free to 
shorten or rewrite the code as you please. The major objective of our code 
is to get the program to do what it is supposed to do and run bug-free. Our 
purposes have been fulfilled by this code. 

In closing, we realize that the material presented in this book might be a tad 
overwhelming for some of our readers, but we chose to leave none of our 
knowledge left unsaid. It is our sincere hope that you may have as much 
fun reading and learning from this book as we did in programming the 
MUSIC AUTO-PLAYER. 

Namaste'- 

Len Dorfman, Dennis Young 
August, 1986 



Chapter 1 


MIDI and Your ST 




















































Abacus Software 


Atari ST MIDI Book 


MIDI and Your ST 


The Atari ST computer line has provided an affordable range of computers 
with unprecedented computing power and value. We were not privy to the 
Atari inner decision-making process which resulted in the MIDI interface 
being installed as standard hardware into the ST. All we know is that it 
affords users of the ST uncomplicated, inexpensive access into one of the 
most exciting and fast-moving of fields: synthesized music. 

Much MIDI software is already on the market and much more is on the 
way. With this software, you can enter the world of the musician. With 
your ST and mouse, you will be able to enter complex musical pieces and 
play them back precisely and crisply every time. For composers, the 
multi-voice capabilities of the keyboard synthesizers will allow them to 
experiment with their pieces with unending flexibility. Singers will be able 
to have their own orchestra on call for instant practice, or as a replacement at 
a performance. Songwriters and composers will be able to have the ST print 
in high-resolution graphics their scores, lyrics and all. For the musician 
who would like to compose directly at the keyboard, have it saved into the 
computer's memory, and then finely tune the notes, the capability is there. 

The MIDI IN and MIDI OUT ports on the back of the Atari ST are the 
connecting points to the magical universe of synthesized music. Before we 
continue with our discussion of MIDI programming, we will digress a 
moment. 

The task of writing music is well beyond the scope of this book, but we feel 
that it is important to explain some basic things that relate directly to the 
mechanics of using your MIDI connection/synthesizer in the music creation 
process. Then too, it would be good to give the uninitiated at least a brief 
smattering of musical notation that they have a chance of testing the 
pleasures that music can yield (without too much work). If you are familiar 
with standard music notation feel free to skip this introduction and GOTO 
Section 1.1. 

Musical notation is the art of expressing music in written form. In modem 
western music this usually means putting notes on a staff. A staff in its 
commonly accepted form is a group of five evenly spaced horizontal lines 
and spaces, each having its own name. Notes are used as symbols and 
placed in such a fashion as to express the two elemental qualities of music, 
duration and pitch. 


3 



Abacus Software 


Atari ST MIDI Book 


Duration 

Duration is the length of time afforded to the playing of a note. The actual 
span of time playing the note will vary depending on the piece's overall 
tempo but within that framework the time spent on equal notes will always 
be equal. Thus, if 2 seconds is spent playing a whole note in measure one, 
and there is no change in tempo, a whole note in measure three will also 
take 2 seconds. In modem use, a whole note is the longest you can select 
and all other notes bear a direct time relationship to it. A half note will take 
half as much time to play, a quarter note will take 1/4 the time to play and so 
on all the way down to the shortest normally used note, a sixty-fourth note. 
For each note there is a corresponding rest. A rest gives us an easy means 
of providing a precise length of time when no sound should be made. 

Dots are used in music to increase by half the length of time a note will play. 
This is done simply by placing the dot following (to the right of) the note. 
If the note is a half note, you would wind up holding it for the same amount 
of time you would normally expend for three quarter notes together. 
Occasionally, you will come across a double-dotted note. In this case, the 
note's value would increase first by a half and then by a quarter of its 
original value. A half note in this case would finish up with the value of 
seven eighth notes (4 + 2+1). Rests can be dotted or double-dotted just as 
notes can and yield the same result. 

A tie is a curved line that connects consecutive notes of the same pitch and 
which has the purpose of combining the two notes into a single sound that 
lasts as long as the total of the two separate durations. It can be used to 
create duration values for a single sound that can't otherwise be had, such 
as seven eighth notes played as one unit: a half note tied to a dotted quarter 
note. The other important use for a tie is to couple two notes that are 
separated by a bar line. 

A slur is similar to a tie except that it connects notes that are not the same. 
For instance, if you connected a C note and a D note you would be using a 
slur, not a tie. 


Many MIDI instruments allow portamento , in which the player "carries " the 
sound from note to note without break - that is, sliding from one note to the 
next in such a fashion that the intermediate notes are passed through. This 
effect is most often used with the trombone or stringed instruments. 


4 



Abacus Software 


Atari ST MIDI Book 


A triplet is yet another device to allow the composer to vary duration. Here 
three notes are performed in the length of time normally allotted for two of 
the same type. An example of this is that a triplet of eighth notes will last as 
long as a quarter note (or two regular eighth notes). 

Generally, you will be moving left to right along the staff and this horizontal 
reading is how music time passes and the piece proceeds. The basic beat in 
most modem music can be counted off in very regular segments such as 
1-2,1-2 // 1-2-3, 1-2-3 // 1-2-3-4, 1-2-3-4 and the like. The duration of 
one of these segments is described as a measure or bar. A measure is set 
off by a vertical line called a bar line and usually a musical piece is 
composed of a collection of these measures. 

The number of beats in a measure is indicated by the time signature. The 
time signature, which is a number, is placed to the left of a double bar line 
that occurs at the beginning of a staff. This number is a fraction such as 3/4 
that has a double meaning. The top number in the fraction yields the 
number of beats in each of the subsequent measures and the bottom number 
designates which kind of note receives the beat. This time signature is in 
effect unless it is superceded by another one. In 3/4 time there would be 3 
beats in the measure // 1-2-3, 1-2-3, 1-2-3, etc. // and the quarter note 
would be the "beat note". If you add up all the separate note duration values 
in a completed measure it will total the value indicated in the time signature. 
Thus, in our example of a 3/4 time signature, you might have a combination 
of a half note and a quarter note, three quarter notes, one quarter note and 
four eighth notes or a variety of other combinations. 

Tempo refers to how fast the whole piece or at least a designated section of 
it is played. Tempo marks like largo, adagio, andante, moderato, allegro, 
presto, prestissimo (which range from slow to fast) are all Italian words that 
by common practice are used to show the speed at which to play a piece. 
They have no absolute value and are open to considerable interpretation. 
You should bear in mind that tempo, no matter what it is, has no effect on 
how the note durations relate to each other. An eighth note will always be 
twice as long as a sixteenth note and a whole rest will always be four times 
as long as a quarter rest 

Tempo and the ability to vary it is a powerful tool in constructing a 
composition's "mood" or "feel". Careful use of it can greatly embellish a 
work and even simple pieces can be enhanced by this device, sometimes 
with but little effort. 


5 



Abacus Software 


Atari ST MIDI Book 


Pitch 

Sound is what results when vibrations in the air beat against our eardrums. 
When the vibrations are slow we refer to the sound as being "low" and 
when they are fast we call the sound "high". It is this speed of vibration that 
determines what we refer to as pitch. Before dealing further with this 
notion, a little more information about our main workspace, the staff should 
be helpful. 

A clef is placed to the left of the double bar line and is the first symbol that 
appears on the staff. The clefs that are used most frequently are referred to 
as the G or treble clef and the F or bass clef. When two staffs are used as 
the work area, as they often are when writing piano music, the top staff is 
marked with a treble clef and the bottom staff with a bass clef. This 
arrangement of the two staffs is referred to as a Grand Staff and its use is 
very common. Ledger or leger lines are short lines that are created to 
accommodate notes that fall either above or below the staffs. 

In musical notation, the pitch of a note is indicated by its vertical position in 
the workspace - the higher the note the higher the line or space that is 
occupied. Pitches are given the alphabet letters A through G as names and 
each letter name is repeated many times. The reason for this is that there is a 
mathematical and acoustical relationship between the notes that have the 
same name. For example, each C note as you go up the staff represents a 
sound that is vibrating at twice the frequency of the previous C note. The 
same is true for each family of lettered notes. The acoustical similarity is 
not clearly understood (at least by us) but is very real - notes lettered the 
same sound remarkably alike though they are, of course, higher or lower 
than their mates. An octave is the name given to the distance between a pitch 
and another having the same name. 

Octaves actually have more identified pitches than the eight lettered steps. 
Sharps and flats are used in front of different notes to create these extra 
steps which brings the total number up to twelve. The distance between one 
of these 12 notes and its neighbor on either side is a semitone or half-step. 
When a sharp is used, it makes the note that follows it one half-step higher; 
when a flat is used, it means the next note should be played one half-step 
lower. Sharps and flats used in this way, along with another symbol called 
a natural, are collectively called accidentals. Naturals are used to cancel out 
the effect of a sharp of a flat which had been established in the 
composition's key signature. 


6 



Abacus Software 


Atari ST MIDI Book 


The key signature is the group of sharps or flats to the left of the double bar 
line that identify the key of the composition. There are as many as 15 
different major keys - each of which has a related minor key - though many 
of them are rarely used. Whenever a note is placed on a line or space that 
has an accidental on it in the key signature, the note automatically assumes 
the value specified. In the key of D major, for instance, all notes on F and 
C should be treated as sharps. In the key of B Major, all notes on B and E 
should be treated as flats. This is where the natural comes in. If you wish 
to temporarily cancel the effect of the automatic sharp or flat, you put a 
natural before the note. 

There are a great many books on music notation available to the interested 
reader in almost any library. Libraries are also a fantastic resource for sheet 
music of all kinds if you will be transcribing pieces for MIDI 
implementation. 


1.1 Our Introduction to MIDI Programming 


One sunny afternoon in the early winter of 1986 one of the people at XLent 
Software called us up asking if we might be interested in writing a program 
for a MIDI synthesizer. We jumped at the opportunity as we had spent the 
better part of the two previous years writing 6502 assembly and ST 'C 
desktop publishing-type projects. We both were music lovers and were 
eager to begin the project. What started out as a promising commercial 
programming venture turned into a labor of love. As we moved into the 
coding for ST MUSIC BOX and the AUTO-PLAYER (whose source and 
more is presented later in the book) our orientation changed from, "How 
will this product be received at computer shows or by reviewers?" to "This 
is our own private music creation designed by us for us. If others get 
pleasure from its use, wonderful; if not, no matter, we stand by the art." In 
a sense, our attitude might be construed as arrogant, but we share it only to 
let you know the depth of our feelings for the pleasure we have received 
from our entry into the world of MIDI through programming the ST 
MUSIC Box and AUTO-PLAYER, and the subsequent use and testing of 
our programs. 

After we agreed to take the project on, we called a local music store asking 
if there were any Keyboard magazines containing MIDI information on 
the shelves. Well, to cut a long story short, all the local stores' shelves 
containing MIDI related magazines and books were picked clean to the 


7 



Abacus Software 


Atari ST MIDI Book 


bone. The more we looked the more we realized that MIDI was not a term 
reserved for an arcane cult of electronic music fanatics. Rather, it seemed to 
be a tidal wave of people from all walks of life touched by music's magic. 

The next day we went out and bought two inexpensive Casio CZ-101 MIDI 
keyboard synthesizers. Within minutes after plugging the units in and 
turning them on we became mesmerized. We were done for; hopelessly 
smitten. We lost our sensibilities and became hooked on MIDI 
MADNESS!! 


1.2 What is MIDI? 


MIDI is an acronym which stands for: 

Musical Instrument Digital Interface 

Simply, MIDI is an industry standard which allows electronic instruments 
to interconnect with controlling devices, which in the specific case of this 
book, will be the ATARI ST. The Atari ST and the electronic keyboard in 
the simplest MIDI configuration one could have. Experienced musicians 
might wish to have a more sophisticated set-up. Well, fortunately for those 
musicians, the MIDI standard was also designed to include the connecting 
of multiple keyboards, auxiliary manual controllers, sequencers and drum 
machines. 

The word Digital comes in because the electronic instruments use numbers 
as elements for the the MIDI alphabet. The word Interface literally means to 
form a common boundary between two differing entities, which in our 
specific case would be the ATARI ST and the CASIO CZ-101 keyboard 
synthesizer. In other words, if we tell the ST to send the CZ-101 
synthesizer the proper numbers, the CZ-101 could Play Beethoven's Fifth 
Symphony. The trick, of course, is to first know the correct numbers and 
then how to transmit them to the keyboard synthesizer. 

Before we go more deeply into explaining some of the ins and outs of the 
MIDI standard, it seems expeditious to discuss the importance of the MIDI 
standard. A few years back some of the electronic giants of the corporate 
music world, such as Casio, Akai, Yamaha, Roland, Moog, etc., decided 
that if there was an industry standard for communicating with their 
instruments it would have a synergistic effect on sales. 


8 



Abacus Software 


Atari ST MIDI Book 


Were they ever correct. This means, excepting items which will be 
discussed a little later in the book, if you understand how to get your Atari 
ST to speak to, say the Casio CZ, you will also know how to have it speak 
to a Yamaha DX series of synthesizers. In fact, you will be able to hook up 
your ST to a Casio CZ and Yamaha DX, if you wish. 

The MIDI standard might be seen in a similar fashion as the record industry 
standard of the long playing record. You buy your record and you can play 
it on a multitude of turn tables connected to dozens of high fidelity 
amplifiers and speakers. The market for the record producers expands 
because their music medium need not be machine specific. The large base 
of high fidelity equipment promotes a large customer base and volume 
sales. The volume sales means that the record producers can keep record 
costs low. The low cost encourages the purchase of more hardware. 

In contrast, let's take a quick look at what has happened in the computer 
industry with the 6502 microprocessor based Atari 800, the Commodore 64 
and the Apple II home computers. You can not take an Atari 800 series 
computer disk and load it into an Apple II and visa versa. That means that 
software publishers do not have the same type of hardware sales base that 
the record producers do. That means sales volume will be lower so product 
cost must be higher. I remember when I bought our Atari 800 a few years 
back for $1200.00.1 was warned by a friend that the hardware outlay was 
miniscule compared to the software outlay. I almost didn't buy my Atari 
800 system for that very reason. 

If you tend to agree with my line of reasoning it is clear that the MIDI 
standard is a GIANT step in bringing the low cost creative power and joy of 
synthesized music into the home arena. MIDI software on the ST will work 
with a variety of synthesizer machines allowing users to expand then- 
musical world beyond previous expectation. 


9 



Abacus Software 


Atari ST MIDI Book 


1.3 The Atari ST Hardware Hook-up 


Hardware is needed for data transmission. In computer-speak, data is 
another word for information, and that information is stored as numbers. 
Computers are VERY good at manipulating numbers. 

Rather than show complex configurations for a multi-MIDI arrangement, 
we have decided to show the elegant simplicity of a beginner's MIDI set-up. 
Please don't be deceived by the words "beginner's set-up"'. In this case an 
inexpensive keyboard synthesizer hooked up to your ST can produce 
resplendently beautiful sounds. They must be heard to be believed! 

If you are planning to expand your current Atari ST configuration to include 
a MIDI device, we strongly recommend that you start with a keyboard 
synthesizer. If you do not have, or wish to have, piano playing skills you 
can consider a miniature keyboard MIDI configuration, such as the Casio 
CZ-101. This powerful Phase Distortion keyboard synthesizer packs plenty 
of punch for the dollar. The only real drawback of this inexpensive gem is 
that the CZ-101's keyboard does not have full sized keys. Their reduced 
size might prove irksome to some. The CZ-1000 has a full sized keyboard, 
but then it is a bit more expensive and you might do well to check 
comparable synthesizers manufactured by other brands before you decide to 
buy. 

You do not have to have piano skills to use a MIDI keyboard because there 
are programs available right now on your Atari ST which will allow you to 
enter music notes into the ST's RAM memory. The programs then, using 
the MIDI language, can transmit the note information to the synthesizer. 
The synthesizer will then spring to a life of its own. 

■Hie powerful CZ-101 synthesizer has been selling of late for under $250.00 
in the U.S. and in our opinion represents quite a bargain. Please understand 
that when it comes to computer expenditures, operate by two laws: 1) Don't 
spend more than what you initially need to get started! 2) Don’t fix 
something if it's not broken. Prices in MIDI-land can range from the 
$250.00 U.S. dollars to figures deep into the thousands. What we are 
saying is that you don't have to bankrupt your savings to get high-powered 
performance. One other note: you will have to spend a bit more if you are 
interested in a more representative piano keyboard synthesizer. 

Many keyboard synthesizers on the market don’t have built-in amplifiers 
and speakers. You can hook up your synthesizer to a receiver or amplifier. 


10 



Abacus Software 


Atari ST MIDI Book 


If you do not own an amplification system you will need to build or 
purchase one. This expense may be kept well under $120 at U.S. prices. 

Now we will get to the actual hook-up. If you look on the back of the Atari 
ST case you will see two ports labeled MIDI IN and MIDI OUT. The Atari 
ST should be configured with the MIDI synthesizer in the following way: 


MIDI OUT 


immmtuinn 


CZ 101 


MIDI OUT 



ATARI ST 


There, that's not too complicated! The MIDI connecting cables are 
composed of standard 5 pin DIN connectors. As you can see from the 
diagram, the hook-up is very simple. You plug one end of a 5 pin DIN 
connector and cable into the MIDI IN port of the Atari ST and plug the other 
♦ end of that cable into the MIDI OUT port of the synthesizer. Conversely, 
you then take the other cable and plug one DIN connector into the Atari ST 
MIDI OUT port and plug the other end of the cable into the synthesizer 
MIDI IN. 

We have one other short tale about our purchasing the 5 pin DIN cables. We 
purchased our Casio CZ-101 synthesizers at a specialized music store in the 
U.S. When the salesperson asked if we were interested in special MIDI 
cables, we said, "Of course!" To make a long story short, they wanted over 
$25.00 U.S. dollars for one set of two connecting, supposedly specialized, 
cables. Instead, we decided to purchase the cables at a local electronics store 
and payed about $5.00 for one set of very nice connecting cables (saving 
double the price of this book for two pair, we might add). The 5 pin DIN 
MIDI cables are standard electronic ware and best bought in a store that 
caters to the electronic trade. 


11 

































Abacus Software 


Atari ST MIDI Book 


1.4 Serial Data Transmission 


The purpose of the hardware hook-up is to allow the Atari ST and the 
electronic synthesizer a pathway to transfer data between each other. The 
language used is composed of electrical impulses. In today's data transfer 
technology there are two widely used methods: Parallel Data Transmission 
and Serial Data Transmission. In Chapter II we will discuss, for those new 
to computers, the differences between the infamous BITS and BYTES. For 
the purposes of this section, it will suffice to say that 8 bits make up 1 byte. 
Having that fact in mind, we can see that parallel data transmission which 
transfers BYTES is a more efficient transfer method than the serial method 
which transfers 1 bit at a time. 

The MIDI creators decided to go with the bit by bit serial transmission 
method. Why? Computers, compared to human time, are VERY, VERY 
fast. Since music is played at human time speeds and both the serial and 
parallel methods of data transmission are fast enough, the MIDI people 
decided to go with the cheaper method. Serial is cheaper than parallel data 
transmission because there are fewer connecting wires needed for serial data 
transmission and serial connectors are cheaper than parallel connectors. 
Also, it was theorized that some nasty grounding problems would be 
avoided by avoiding the parallel method of data transmission and going with 
the serial method. The cheapest method of data transmission means lower 
product costs and the consumers and electronic manufacturers benefit alike. 
A wise decision. 

For those familiar with computer communications we offer the following 
comparison. One industry standard data transmission rate is the well known 
300 baud. The rate descriptor, 300 baud means this: 300 bits of information 
are being transferred every second. The MIDI standard calls for 30,000 bits 
to be transferred every second. In other words, the MIDI transmission rate 
is 100 times faster that one industry standard. Needless to say, the MIDI 
serial transmission rate is plenty fast for its purpose! 


12 



Abacus Software 


Atari ST MIDI Book 


1.5 Qualities of MIDI SPECIFICATION 1.0 


Although the MIDI SPECIFICATION 1.0 document is not massive in 
length, it is quite deep in nature. In an effort to present the complexity of the 
MIDI SPECIFICATION 1.0 in as clear a fashion as possible, we have 
decided to break the specification into two sub-categories. They are: 

MIDI STANDARD and MIDI LANGUAGE. 

The topic MIDI IMPLEMENTATION is a response to the MIDI 
STANDARD and MIDI LANGUAGE. In the rest of this section we will 
continue to refine these categories. We will do this at length because they 
will appear often in our book, and having a common vocabulary is a crucial 
component in your acquiring information. 

The MIDI STANDARD refers to a concrete description of the total 
communication structure between electronic synthesizers and related 
devices, such as the Atari ST computer. This includes both the hardware 
apparatus, cables, and certain properties of the electronic synthesizers. For 
example, saying that a synthesizer should have the electronics built in to 
allow the Atari ST to send a message over a cable to turn a note on and off 
is to discuss the MIDI STANDARD. To say that a keyboard should have 16 
channels is to discuss the MIDI STANDARD. 

The MIDI LANGUAGE, which will be the main topic of Chapter II 
involves the nature of the data which is transferred between the Atari ST and 
the synthesizer. This language is composed of sequences of numbers and 
can be spoken using any programming language which allows you to access 
the MIDI interface within the input/output structure of the ST. Virtually all 
languages we have encountered allow such interaction. 

A MIDI IMPLEMENTATION refers to the physical presence of what the 
MIDI STANDARD call for. For example, one sound quality a note may 
possess is VIBRATO. VIBRATO is outlined in the MIDI STANDARD. 
The IMPLEMENTATION in one synthesizer might allow the Atari ST 
owner to turn the VIBRATO on and off, to set the rate, and depth. Another 
synthesizer might not allow the changing of the VIBRATO rate and depth. 
We could say in that instance that the two synthesizers did not have the 
same IMPLEMENTATION of the MIDI STANDARD. 


13 



Abacus Software 


Atari ST MIDI Book 


In a little while we are going to outline some ideas which you may consider 
when beginning your shopping for a MIDI synthesizer. One thing we will 
encourage you to do is examine the MIDI IMPLEMENTATION of 
individual synthesizers to assess which one will best fit your needs. 

In summary, the MIDI SPECIFICATION 1.0 lays out the overall structure 
for the hardware interface and the communication protocol between 
electronic musical instruments and the Atari ST. In this book we are calling 
that aspect of the IMPLEMENTATION the MIDI STANDARD. The part of 
the SPECIFICATION which outlines the nature of the MIDI data and its 
syntax we call the MIDI LANGUAGE. 

Any time there is a standard set up there will always be people who say, 
That standard isn't good enough for me!" Or people who say, "People 
don't need all of the features contained in the standard!" The MIDI 
originators decided to create a baseline standard and then allow individual 
manufacturers to add bells and whistles to that standard. 

The keyboard synthesizer's trademark is a piano-like keyboard inlaid in a 
small case. Within the case are a variety of electronic devices used to 
produce the notes, generate a multitude of instrument simulations and hook 
into other MIDI-related devices. 

In the following paragraphs we will describe some of the more important 
features of the keyboard synthesizer. For this, we will also need to define a 
series of both musical and MIDI terms. Understanding the vocabulary at 
this juncture will allow for easier reading as you continue in the book. Since 
it is our experience that many people become confused by the differences 
between, say, MODES and CHANNELS, we have consciously decided to 
explicitly state these terms' meaning when they are used in key sections in 
the book. Although this method of organization might well seem redundant 
to some, we are willing to belabor certain points and risk flak for this 
repetitive style in an effort to reinforce the learning of key MIDI concepts. 

There is one other point to know before we continue. Not all of the features 
described in the following paragraphs will be operative on every synthesizer 
on the market. You will need to read your synthesizer manual very carefully 
in order to know whether your synthesizer has the feature in question. For 
example, not every synthesizer allows the user to change its VELOCITY (a 
measure of note loudness). For one of those synthesizers it would appear 
that sending a VELOCITY message to a synthesizer which doesn't have 
adjustable velocity does no harm. The message should be ignored. 


14 



Abacus Software 


Atari ST MIDI Book 


Now, to begin: 

Pressing a key will produce the sound of a NOTE which corresponds to the 
note's frequency. By that we mean, if you press the middle 'C key on the 
keyboard, the middle 'C' note will play. That is simple enough. 

Pressing a key is not the only way to play a note on a synthesizer, though. 
Your Atari ST, after being properly hooked up to your synthesizer, might 
just as easily send a NOTE ON message through the 5 pin DIN connecting 
cables. Like electronic magic, the note will play. Sending the NOTE OFF 
message will, conversely, turn the note off. 

NOTE ON and NOTE OFF messages are not the only information that the 
Atari ST can SEND and RECEIVE. RECEIVE? Yes, the ST can also 
"mind meld" with the synthesizer to read and remember all that transpires by 
human initiation on the keyboard. 

The INSTRUMENT VOICE means the simulated tone the synthesizer is 
producing. Some common instruments available on keyboard synthesizers 
are flute, bass, trumpet, piano, whistle, oboe, etc. For example, you might 
select the flute INSTRUMENT VOICE tone to be used as you play notes on 
the synthesizer. Then when you press keys it will produce a sound close to 
that of a flute. 

PROGRAM CHANGE or PROGRAM SELECT refers to the process of 
changing the instrument voice that the synthesizer is playing. The 
instrument voices can fall into three catagories: PRESET, INTERNAL, and 
CARTRIDGE. The PRESET voices are assigned numbers ranging from 
1 - 32. These instrument voices are preset at the synthesizer factory and 
can not be changed by the programmer. The PROGRAM CHANGE 
numbers 33 - 64 have been reserved for the internal instrument voices. 
These voices may be created by the synthesizer user (see PROGRAMMING 
YOUR SYNTHESIZER) and are either remembered by the synthesizer or 
are transferred to the synthesizer from your Atari ST. PROGRAM 
CHANGE numbers 65 - 96 are reserved for plug in CARTRIDGES. These 
special cartridges have the ability to add even more special instrument voices 
to your already impressive assortment of choices. This change can be 
accomplished manually or by having the computer, using the appropriate 
MIDI language code, enable the PROGRAM CHANGE. 

The speed at which you press the key down is called the VELOCITY. 
Generally speaking, the quicker you press the key the more dynamically, or 
loud, the note will play. 


15 



Abacus Software 


Atari ST MIDI Book 


The AFTERTOUCH refers to the amount of pressure you, as the player, 
put on the key you are pressing. For example, had you previously selected 
the flute, increasing the AFTERTOUCH would simulate the flute player 
blowing a greater volume of air as (s)he played. 

VIBRATO is the pulsating effect heard when a note is played. The 
VIBRATO rate, the speed of the pulsation in the sound, and the depth, the 
intensity of the pulsation, can be controlled. 

PORTAMENTO, to the ear, sounds as a musical slur. Say you play the 
notes middle 'C' and then the D' above middle 'C'. You will hear two 
distinct notes with two distinct frequencies. As you increase the 
PORTAMENTO time the distinction between the 'C' and 'D' will begin to 
disappear. The notes will begin to merge together so that the lower 'C* note 
will gradually increase in frequency and glide to the higher 'D'. 

The PITCH BEND or PITCH WHEEL allows the player to glide the 
frequency of the playing note in either direction with a turn of the PITCH 
WHEEL. The range of the glide is controlled by the PITCH BEND or 
PITCH WHEEL setting. 

MIDI keyboards have 16 CHANNELS available to play through. Using 
your MIDI software you might select the bass instrument voice to play 
through MIDI CHANNEL 1, and the flute instrument voice to play through 
CHANNEL 2. Some synthesizers will allow you play 16 different 
instrument voices on the 16 available CHANNELS. The BASIC 
CHANNEL may defined as a kind of bottom foundation CHANNEL. For 
example, in the Casio CZ-101 electronic keyboard synthesizer you may set 
the BASIC CHANNEL to, say, 5. This would mean that the Casio would 
respond to note on and note off messages on CHANNELS 5, 6, 7, & 8. 
We refer you to a Casio manual for the reason why this will occur, but its 
importance cannot be over-emphasized. For example, the Casio CZ 101 
can play instrument voices out of a maximum of four CHANNELS. If you 
hooked up two Casios together and set one's BASIC CHANNEL to 1 and 
the other's BASIC CHANNEL to 5 you could send 8 voices of music from 
the Atari ST to your two Casio synthesizers. The CZ-101 with its BASIC 
CHANNEL set to 1 will play all note on and note off messages on 
CHANNELS 1 - 4. The CZ-101 with its BASIC CHANNEL set to 5 will 
play all note on and note off messages on CHANNELS 5-8. That way, 
two CZ-lOls could play 8 voices! 


16 



Abacus Software 


Atari ST MIDI Book 


The MIDI standard calls for four different keyboard MODES. The MODE 
that the synthesizer is set to determines how it will interpret and 
consequently play incoming note data. The MODES are: OMNI ON/POLY, 
OMNI ON/MONO, OMNI OFF/POLY and OMNI OFF/MONO. 

The OMNI/POLY or OMNI MODE sets the electronic keyboard to receive 
note information on any of the synthesizer's 16 channels. The catch is that 
all 16 voices are played using a single instrument voice. For example, if 
you were feeding the synthesizer a four-part fugue, each part would be 
assigned an individual channel. But, each channel would have the same 
instrument assigned to it. So you might choose to have four flutes, or four 
whistlers, or four violins playing the fugue. This MODE might prove useful 
to someone who for some reason needs a decent sounding piece quickly and 
is a very beginner with keyboard synthesizers. With a bit more time the 
beginner can learn how to do much more than the OMNI/POLY MODE will 
allow. Overall, it seems that the OMNI/POLY MODE isn't too useful. 

The OMNI ON/MONO mode will take all the note messages that are coming 
into the keyboard and put them in just one voice. Simply stated, if you sent 
16 voices of note data from your Atari ST, it would come out as a single 
line of music. This playing of a single note at a time would eliminate the 
playing of chords. It would sound hollow compared to a full voice 
implementation. This mode produces sounds similar to how the early model 
synthesizers sounded as they also allowed only one note to be played at a 
time. The OMNI ON/ MONO mode does not seem very useful when using 
one keyboard synthesizer. 

The OMNI OFF/ POLY or POLY mode requires that the Atari ST and the 
keyboard synthesizer be tuned to the same channel for data transfer. If, say, 
the Atari ST was sending note data on channel 1 and the keyboard 
synthesizer was set to receive on channel 2, no sound would be played. As 
with the previous two modes, the OMNI OFF/ POLY mode might prove 
useful in a multi-MIDI implementation, but for the single MIDI 
implementation it serves poorly. 

Don't get disheartened. We've saved the best for last. The OMNI OFF/ 
MONO mode is the mode of choice for the single MIDI keyboard 
implementation. The mode will allow the user to transmit from the 
computer 16 voices, with one voice appropriately being sent to each 
channel. EACH CHANNEL MAY HAVE ITS OWN INSTRUMENT 
VOICE! This means that channel 1 could play a flute, channel 2 a violin, 
channel 3 a snare drum...etc. It is in the OMNI OFF/ MONO mode that the 
power of the Atari ST and the keyboard synthesizer come to shine. 


17 



Abacus Software 


Atari ST MIDI Book 


We do believe that part of the confusion surrounding the OMNI/MONO 
mode is its very name. MONO seems to imply, at least to us, that it will 
play one voice. In fact our initial confusion with the powerful MONO mode 
came when we fired up our Casio synthesizers. Why? Because if you 
press the MONO button on our CZ-101 you can play only one note at a time 
from the keyboard. With the button in the up position you could play 
chords. So when we tested the first code for the player we did not press the 
MONO button. All we heard was a single line of music playing. We nearly 
went to the looney bin trying to figure out what was happening. We then 
pressed the MONO button out of desperation, and presto, all four voices 
played with great pride. Pressing the MONO button on the Casio to achieve 
multi-voice play seemed rather daffy, but so it is, and so it goes. 

The distinctions between the MIDI MODE, CHANNEL, INSTRUMENT 
VOICE and PROGRAM CHANGE can be confusing at times. As we 
encounter these terms later in the book they will be explained again. 
Hopefully, the repetition and clarity will bring greater understanding. 

As we suggested earlier in this chapter one of the powerful aspects of 
electronic synthesizers is their ability to simulate the sound of different 
instruments. The range of synthesizer sounds extends far beyond the 
number of traditional acoustic instruments. 

There are a variety of electronic methods for synthesizing sounds. Some 
among then have names such as: Analog, Digital Phase Distortion, Digital 
FM, and cousins and combinations of the previously mentioned three. At 
this point in the book we could give a brief discourse on each of the 
mentioned electronic methods of synthesizing sound, but we feel that the 
discussion would be too tangential for the goals of this book. What we 
view as more important is: How difficult is it for the synthesizer owner to 
change the quality of sound that the synthesizer produces? 

The electronics of synthetic sound generation allow for a variety of 
parameters to be adjusted. Altering the numerical values of these parameters 
will change the sound that the synthesizer is producing. The methods used 
to change the numbers which describe the synthesizer's sound are most 
often different for varying brands of synthesizers and are traditionally 
explained in full detail in the synthesizer's operating manual. 


18 



Abacus Software 


Atari ST MIDI Book 


We have reached another point where it is once again beneficial to define a 
few more terms. It is common practice in magazines and books aligned 
closely to the music industry to refer to altering the numbers which change 
the sounds that the synthesizer is producing as "PROGRAMMING THE 
SYNTHESIZER". As we come from the computer programming 
community we feel that some readers might be confused by that term. 

It is for this reason that when referring to programming the Atari ST, we 
will specifically state that case. For example, we might say, "If you enter 
the source code for the program ' sample. c' into your Atari ST and then 

use your 'C' compiler and assembler.". We will adhere to what appears 

to be an accepted music writing industry convention of referring to 
"programming the synthesizer" as that process of altering the numbers 
which change the sound qualities of the notes produced. 

If this proves an inconvenience, we apologize, but clarity in transfer of 
information is one of our primary goals. We would rather add a few extra 
words than leave the reader more confused than need be. Also, when you 
encounter the phrase "Programming your Synthesizer" in Keyboard or 
Keyboards & Computers magazines, you will immediately know that 
you will NOT find a program for your Atari ST. 

Collections of the numbers which tell the synthesizer what type of sound to 
play are generally called PATCHES. The word PATCHES is a throwback 
to the early days of synthesizers where patches of connecting wires were 
used to alter the synthesizer's sounds. PATCHES are made up of numbers 
with the formal names of TONE DATA or SOUND DATA. Restated: 

TONE DATA or SOUND DATA refers to the parameters, or number 
settings which make the synthesizer voice sound the way it does. The 
Casio CZ-101 allows the programmer and synthesizer player to change a 
veritable cornucopia of parameters. Some include: Line Select, Ring, Noise, 
Vibrato Rate, Vibrato Depth, various Wave Forms, Envelope Shape...etc. 

We hope that you are beginning to see the richness and fantastic musical 
opportunities afforded to the owners of the Atari ST and electronic 
synthesizers. This book will give the musician Atari ST owner and the 
programming professional and casual user alike a wealth of ideas for fun 
projects. But, know that as much as is presented here, this book only 
scratches the surface of the ever-changing universe of electronic music. 


19 




Abacus Software 


Atari ST MIDI Book 


1.6 Programming Your Synthesizer 


Programming your synthesizer is not programming your Atari ST 
computer. It is the method used to change the ways the synthesizer sounds 
are generated. 

Traditionally, the buttons, wheels and dials used to change the quality of the 
synthesizer's sounds are located on the synthesizer's cabinet. Each control 
device is attached to a part of the electronic circuitry which will change the 
produced sound in some way. For the purposes of this discussion we will 
say that a PARAMETER represents an aspect of the synthesizer's sound. 
The PARAMETER can have many different settings and can be adjusted by 
one of the control devices on the synthesizer's case. For example, vibrato 
would be an example of a sound parameter. 

Here is a precisely described example of how you might program the Casio 
CZ-101 to change the vibrato for a voice. The instructions are in English. 
The parameter of the vibrato we are changing is the vibrato WAVE FORM. 
If you have a CZ series synthesizer and you are not familiar with 
programming it yet, now might be a good time to try this little example. 

1) Turn on the CZ-101 synthesizer 

2) Press the gray #2 button for switching on the preset voice 2 
internal sound quality. 

3) The vibrato ON/OFF light will go on. Press the gray vibrato 
button. 

4) The LCD text window will display: 

WAVE=1 DELAY=27 RATE=49 DEPTH=49 

5) Notice the blinking underscore below the 1 next to WAVE. 
Press the UP ARROW KEY. 

6) Now the WAVE=2. 

There you have it! All that just to change the vibrato WAVE FORM. 

Not all sound parameters are the same for each electronic synthesizer. For 
example, the Casio CZ-101 uses the Phase Distortion method of electronic 
sound synthesis. Returning to the previously mentioned text display in the 
CZ's LCD window, there are four parameters mentioned in the CZ's 
description of the vibrato sound. Another brand of synthesizer might call 
those parameters by different names, only have two of the four parameters, 
or not have vibrato at all. The features your synthesizer has are all 
determined by its MIDI IMPLEMENTATION. 


20 



Abacus Software 


Atari ST MIDI Book 


There is not a one-to-one relationship between a synthesizer's SOUND 
DATA (the actual numbers) and the sound that is produced by the 
synthesizer. In fact, creating a sound can be somewhat tricky. For 
example, say your synthesizer has two parameters called "A" and "B". "A" 
is set to 49 and "B" is set to 70. You do the following: 

1) Listen to the sound. 

2) Change "A” from 49 to 10. 

3) Listen to the sound. There is no change in the sound! 

4) Change ”B" from 70 to 90. 

5) Listen to the sound. There IS a change in the sound. 

5) Return to "A" and change "A" from 10 back to 49. 

6) Listen to the sound. There IS a change in the sound! 

The change in "A" did not affect the sound until "B"'s setting was at 90. 
Another way to describe what we are trying explain is to say that "A" and 
"B" have a mutually symbiotic relationship. Changing one member in the 
SOUND DATA'S number set may change the relationship of the other 
SOUND DATA to the sound that the synthesizer produces. 

We are not done with our discussion of programming your synthesizer yet! 
There is a way to have your Atari ST X-ray your synthesizer's SOUND 
DATA and store the SOUND DATA for a particular voice on a disk file. 
The type of program that does this can be called a PATCH EDITOR or 
PATCH LIBRARIAN. PATCH EDITORS can also tell your Atari ST to 
send the SOUND DATA back to your synthesizer. The SOUND DATA 
loads to any INTERNAL or RAM CARTRIDGE voice. The reason why 
some companies call their PATCH related programs LIBRARIANS is that 
they have the capability of storing literally hundreds of sound PATCHES 
on disk. The patch files could be called your LIBRARY of SOUNDS. 

There are many ways to begin developing your skills as a synthesizer 
programmer. We suggest that you use two time-honored methods of 
learning. First, start out with a PRESET VOICE. Get a pencil and paper 
and begin, in an organized fashion, to change one sound parameter at a 
time. Listen to the change. Change it a little more. Listen to the sound again. 
Write your impression of what your change did. Select another sound 
parameter...and continue the process until you feel that it is time to stop. 
The second way would be to search out the magazines and books to look 
for other people's published patches. Program them into your synthesizer. 
Listen to the results. Follow the first procedure described. Learning to 
program a synthesizer is a prime example of the maxim: Experimentation is 
the mother of invention! Enjoy! 


21 



Abacus Software 


Atari ST MIDI Book 


1.7 A Guide For Buying Your Synthesizer 


Clearly, many people are fascinated with the electronics of sound synthesis. 
For the purposes of this book, though, we will argue that the end result of 
how the synthesizer sounds and how easy it is to program (remember... 
"programming the synthesizer") is more important to most users than the 
electronics of producing the sounds. 

For most applications, if you've got $1,500 to spend you'll have little 
trouble finding a full-featured keyboard synthesizer for most applications. 
Since we didn't (and still don't) have $1,500 to spend on a full featured 
synthesizer, we reasoned that it would make sense to lay out a few points to 
think about when planning the purchase of your first MIDI keyboard. 

The first question we would place on our list would be, "Do you or does 
anyone in your family play the piano?". If the answer to that question is 
YES, then it would be wise to bring the person or people along to test out 
the action of the synthesizer. Keyboards can have different key responses 
and different numbers of keys making up the keyboard. If there is a choice 
between two equals, the feel of the keyboard or the number of keys it 
contains might present a deciding factor. If the answer is NO then you 
might be able to look at some keyboard synthesizers which have reduced 
size keyboards. 

What modes may be enabled by the synthesizer? Some of the MODES 
might prove useful in multiple electronic instrument implementations. Is 
that a consideration for you? 

Another matter to consider would be to explore how many instrument 
voices could be played in the synthesizer's MONO mode. If you remember, 
the MONO mode allows each voice to be played through an individual 
channel while having a different instrument selected. The number of 
channels used for the MONO mode currently ranges from 4 to 16 channels. 
Will having four individual voices using four individually defined 
instruments suffice? If not, how many will you need for your application? 
Six? Eight? It appears that the more channels you wish to have available to 
you in the MONO mode, the higher the cost. 


22 



Abacus Software 


Atari ST MIDI Book 


How is the MIDI STANDARD represented in the synthesizer's MIDI 
IMPLEMENTATION? Remember that the keyboard synthesizer can receive 
data from your Atari ST and also transmit data to your Atari ST. The 
keyboard will receive data if, say, your Atari ST has software which is 
communicating using the MIDI LANGUAGE and telling it to play a song. 

The keyboard synthesizer will be transmitting data to the Atari ST if you are 
playing a song at the keyboard and wish to have your Atari ST remember all 
the notes that have been played. Sometimes synthesizers do not have the 
same MIDI IMPLEMENTATION for the transmitting to the Atari ST and 
the receiving from the Atari ST. For example, the Akai AX60 keyboard 
synthesizer can transmit a velocity value, but it cannot receive a velocity 
value. 

The manuals for the synthesizer in question will have a copy of the 
electronic instrument's MIDI IMPLEMENTATION CHART. This chart is 
composed of four columns which describe the synthesizer's MIDI 
IMPLEMENTATION. They are: 1)MIDI FUNCTION, such as velocity, 
after pressure, pitch bend...etc.; 2) TRANSMIT, whether it transmits 
information to implement the function in question; 3) RECEIVE, whether it 
receives information to implement the function in question; 4) REMARKS, 
contain a brief space for special explanations. It might pay to have a careful 
look at the MIDI IMPLEMENTATION chart of any synthesizer you are 
considering buying. 


23 



Abacus Software 


Atari ST MIDI Book 


Date: 

Model MIDI Implementation Chart Version: 


Function... 

Transmitted 

Recognized 

Remarks 

Basic Default 

Channel Channel 




Mode Default 

Messages 

Altered 




Note 

Number True Voice 




Velocity Note ON 

Note OFF 




After Key’s 

Touch Ch's 




Pitch 

Bender 




Control 

Change 




Prog 

Change True # 




System Exclusive 




System : Song Pos 

: Song Sel 
Common : Tune 




System : Clock 

Real Time : Commands 




Aux : Local ON/OFF 

: All Notes Off 

Mes "„ : Active Sense 
sages _ . 

: Reset 




Notes 





Mode 1 : OMNI ON, POLY Mode 2 : OMNI ON, MONO X: Yes 

Mode 3 : OMNI OFF, POLY Mode 4 : OMNI OFF, MONO O : No 


24 






















Abacus Software 


Atari ST MIDI Book 


Price, of course, will have a critical impact on which keyboard synthesizer 
you choose to get. Finding the price/performance ratio which suits your 
needs best is the trick. Here is a partial list of MIDI keyboard 
manufacturers: Akai, Casio, Chroma, Korg, Oxford, Roland, Seiko, Siel, 
Sequential, Suzuki, Wersi and Yamaha. Prices range from a few hundred 
dollars up to the $1,500 (U.S.) range. In the New York area the best places 
to shop for the electronic keyboard synthesizers turned out to be the 
rock/jazz music shops. Although it was mild culture shock for us 
middle-aged folks to wander amongst the young'uns, it was well worth the 
effort. The selection of electronic keyboard offerings in these establishments 
far surpassed those in the standard piano stores we visited. We chose to 
buy Casio CZ-101 keyboard synthesizers. This model has a reduced-size 
keyboard and 4 channels operative for instrument voice assignments in the 
MONO mode. We chose this model because it was the cheapest we could 
find with the minimum MIDI IMPLEMENTATION needed to write ST 
MUSIC BOX and our AUTO-MUSIC MIDI PLAYER. Are we happy? 
Yes and no. The CZ-101 does everything it is billed to do. When we were 
keying in our demonstration tunes for some computer shows where the ST 
MUSIC BOX was going to be shown, there were times when I wished the 
CZ-101 allowed for the playing of 8 instrument voices through 8 channels 
rather than the 4 permitted by its MIDI IMPLEMENTATION. It would 
have permitted dramatically more impressive musical arrangements for the 
demonstration songs. Would the reception of ST MUSIC BOX have been 
different by the press and distributor's if we had used 8 instrument voice 
demonstrations rather than 4 instrument voices? Who knows. Our second 
consideration was the reduced size keyboard. Neither of us have 
sophisticated keyboard skills (Len is a well-trained jazz guitarist) so we 
decided that the reduced size keyboard wouldn't matter. But- Len has a 
twelve year old daughter and Dennis has two children who might like to 
have a full sized piano keyboard to play on. 

In retrospect, I suppose we would have gone for the Casio CZ-1000, with 
its 49-full sized keys. We would still have forgone the 8 instrument voices 
as a non-necessary luxury. Good hunting! 


25 



Abacus Software 


Atari ST MIDI Book 


1.8 A Guide for buying Your MIDI Software 


We have been on both ends of the software industry. We are users. We are 
software designers and assembly/'C' programmers. We have read reviews 
and bought products and our products have been reviewed and bought. We 
know everyone has their opinions, and so do we. Here are our thoughts 
from a user perspective. In Chapter III we will present our programmer 
perspective as we begin the massive operation of explaining the logic 
structure for the 'C' source code presented in this volume. 

First we will consider some qualities in programs where the electronic 
keyboard takes on the role of the receiver and the Atari ST is telling the 
keyboard what to do. 

Before we begin, we need to define a few musical terms for those not 
familiar with their meanings. 


Tempo 

Duration 

Key 

Manuscript 

Editor 


the speed at which the song is played 
how long a note is held 
here, the foundation or home note 
here, written or printed music 
program used to enter musical notes 


When determining what software you should first begin by assessing your 
own needs. For example, do you need to print the manuscript? Do you 
need to have all the pieces and/or voices displayed at the same time on the 
printed manuscript? Do you compose for a piano? Do you compose 
classical quartets? Are you a popular song composer and need more than a 
rudimentary text inclusion function in order to print your newest hits? 

What do you need in the editor? What is the method of note entry? How is 
the editor structured? Does it use the mouse? Are the functions like 
INSERT MEASURE, DELETE MEASURE? 


Once you have entered the notes into the music editor how will the notes be 
played? What are the MIDI functions which can be written to? Can you 
control the instrument voice per line of music? Can you have different 
instruments per voice? When do you select the instrument? Per song? Per 
measure? Per note? When do you select the song's tempo? Per song? Per 
measure? Per note? 


26 



Abacus Software 


Atari ST MIDI Book 


Once again we need to define another MIDI world buzz word. 

REAL TIME CAPTURE is the ability of an Atari ST computer program to 
receive the keyboard information transmitted FROM the MIDI electronic 
keyboard and store it in memory. Once the song information is in memory 
then you will be able to alter it any way you want. REAL TIME CAPTURE 
might be an important feature if you have keyboard skills where you would 
want to play a song, rather than enter the notes with an editor and let the 
Atari ST play the song. 

What are you going to use the MIDI software for? If you don't play the 
piano, REAL TIME CAPTURE may not be a useful feature to have. What 
type of manuscript print program suits your needs best? If you're not too 
familiar with entering music into an editor, then getting a smart one with a 
syntax check would probably be smart. If you sing, getting a program 
which would allow you to change the song's keys would be a critical 
feature in adjusting the music to your range. 

We've presented some ideas for you to chew on. Our advice is to look 
carefully when examining the software you are considering for purchase. 
Ask to see the programs demonstrated at your local computer store. Talk to 
friends who are already using MIDI software. If you ask yourself some of 
the questions we raised in the preceding paragraphs and then answer them, 
you will be well on the way to finding the MIDI program for you. 

One other note: we do a great deal of writing. Some of the writing is either 
'C' or assembly source code. We also write non-fiction and have dabbled 
in fiction. We use three text editors on the Atari ST computers and two text 
editors on our 130XE computers. We use so many because each editor is 
slightly different from the next one, and each one fills a different need based 
on the type of writing we are doing. What we are saying is that if you are 
serious about entering the splendor of MIDI-land you just might want to 
have a few Atari ST MIDI programs to work with. Just a thought. 


27 



Abacus Software 


Atari ST MIDI Book 


1.9 Chapter 1 Summary 


In Chapter I we explained that the MIDI SPECIFICATION 1.0 is a 
mutually-agreed-upon standard of hardware and software principles, 
allowing electronic musical instruments and computers to speak with each 
other. For convenience we broke the MIDI SPECIFICATION 1.0 into two 
distinct categories. The first we called the MIDI STANDARD. This 
category included all the interface hardware and a base line standard of 
electronic synthesizer functions. The other category derived from the MIDI 
SPECIFICATION 1.0 is the MIDI LANGUAGE. This is the language 
which you program your Atari ST to use in communicating to the electronic 
synthesizer. MIDI LANGUAGE is the primary subject of Chapter n. 

The functions of the electronic synthesizer allow your Atari ST to send 
messages through the interconnecting 5 pin DIN cables to your synthesizer 
which will command it to play songs with amazing versatility. Also, the 
Atari ST can function as a receiver, remembering all the action on the 
synthesizer keyboard. It is the software running the Atari ST which 
determines how it will communicate with the electronic synthesizer. 

Programming your synthesizer means changing the sound quality produced 
by one or more of the synthesizer's instrument voices. Programming the 
Atari ST means telling the ST how you wish it to communicate with the 
synthesizer. In this book, programs for the Atari ST will be written in the 
'C' programming language. There are now a goodly number of fine 'C' 
compilers available for the Atari ST and many 'C programming instruction 
texts on bookstore shelves. 


28 



Chapter II 


The MIDI LANGUAGE 


































Abacus Software 


Atari ST MIDI Book 


The MIDI LANGUAGE 


The Atari ST is connected to your keyboard synthesizer by the 5 pin DIN 
cables plugged at one end into the synthesizer's MIDI ports and at die other 
end into the ST's MIDI ports. The connecting cable will cany electrical 
impulses between the synthesizer and the ST. These electrical impulses will 
represent numerical values. 

The MIDI LANGUAGE, in a sense, can be considered a mathematical 
language where the basic communication elements are clusters of numbers. 
In this chapter we will define what the clusters of numbers mean. The 
process of getting your Atari ST to bring the synthesizer to life is to have the 
ST send the appropriate clusters of numbers through the connecting MIDI 
cable to the synthesizer. 


2.1 BITS & BYTES 


For purposes of enriching this chapter for those not familiar with the world 
of BITS & BYTES, we have decided to include the information presented in 
this section. If you are familiar with these sacred computer concepts then 
GOTO section 2.2. 

The MIDI STANDARD calls for the special number clusters of the MIDI 
LANGUAGE to be held in bytes. A BYTE may be thought of as a 
container which can hold numbers with values ranging from 0 to 255. 
When you say you are sending a BYTE of information, all you are saying is 
that you are sending a number between 0 and 255. 

A BYTE is composed of 8 BITS. Following the previous analogy of a 
BYTE being a container, the 8 BITS could be conceived of as an 
arrangement of 8 compartments in the container. Each BIT compartment 
will have a specific location with number identifiers ranging from 0 to 7. 

Still with us? Each of the 8 BIT location compartments can have either a 0 
or 1 in them. The numerical value of the BYTE is determined by the 
specific BIT compartments which hold Is. Table 2.A is a CONVERSION 
TABLE showing the relationship between the BIT COMPARTMENT 
LOCATION and DECIMAL CONVERSION number. 


31 



Abacus Software 


Atari ST MIDI Book 


Table 2.A 

COMPARTMENT 

DECIMAL CONVERSION IF BIT 

LOCATION 

COMPARTMENT HOLDS a 1 

0 

1 

1 

2 

2 

4 

3 

8 

4 

16 

5 

32 

6 

64 

7 

128 


If ANY BIT COMPARTMENT holds a 0 the conversion number will 
ALWAYS be 0. 

The process of converting a number from BINARY to DECIMAL is really 
quite simple. For purposes of this book we will explain how to convert 
BINARY numbers to DECIMAL numbers starting with BIT 
COMPARTMENT LOCATION 7. Here is the process: 

BINARY to DECIMAL BYTE 

1) Start with a variable we'll call BYTE set to 0. 

2) Examine BIT COMPARTMENT 7 of BINARY NUMBER. If it 
holds a 1 then add the DECIMAL CONVERSION number for 
BIT LOCATION 7 (128) to BYTE (see Table 2.A if you don't 
understand where the 128 comes from). 

3) Examine BIT COMPARTMENT 6 of BINARY NUMBER. If it 
holds a 1 then add the DECIMAL CONVERSION number for 
BIT LOCATION 6 (64) to BYTE. 


32 








Abacus Software 


Atari ST MIDI Book 


9) Examine BIT COMPARTMENT Oof BINARY NUMBER. If it 
holds a 1 then add the DECIMAL CONVERSION number for 
BIT LOCATION 0 (1) to BYTE. 

10) Variable BYTE holds the DECIMAL equivalent of the BINARY 
number. 

The numerical value of a BYTE is composed of the addition of all the BIT 
DECIMAL CONVERSION VALUES. If all the BIT compartments hold a 
value of 1, then all the DECIMAL CONVERSION VALUES would be 
summed to get the BYTE value. You would have: 1 + 2 + 4 + 8+ 16 + 32 
+ 64 + 128 = 255. If every one of the 8 BIT COMPARTMENTS held a 1, 
and all the DECIMAL CONVERSIONS were used for the BYTE 
SUMMATION, the maximum value of the total would be 255. That is why 
a BYTE (composed of 8 BIT COMPARTMENTS) can hold a number no 
higher than 255. 

Let's try to figure out the decimal value of a BYTE with the following BIT 
COMPARTMENT arrangement. See Table 2.B. 

See that the COMPARTMENT LOCATIONS range between 0 and 7. The 
COMPARTMENT VALUES either hold a 0 or 1. Note that if the 
COMPARTMENT VALUE is 0 the CONVERSION VALUE is ALWAYS 
0. If the BIT COMPARTMENT VALUE holds a 1 the the DECIMAL 
CONVERSION value is determined by the BIT COMPARTMENT 
LOCATION. 

In Table 2.B we see that BIT COMPARTMENT LOCATION 0 holds a 0. 
Following the previously mentioned rule: THE DECIMAL CONVERSION 
is ALWAYS 0 if the BIT COMPARTMENT holds a 0. In column 3, 
CONVERSION SUMMATION, the value is 0 on the COMPARTMENT 
LOCATION 0 row. 


33 



Abacus Software 


Atari ST MIDI Book 


Table 2.B 

Compartment 

COMPARTMENT 

CONVERSION 

Location 

VALUE 

SUMMATION 

0 

0 

0 

1 

0 

0 

2 

1 

4 

3 

1 

8 

4 

0 

0 

5 

1 

32 

6 

0 

0 

7 

1 

128 


BYTE VALUE = 

172 


In Table 2.B we see that COMPARTMENT LOCATION 2 is the first 
COMPARTMENT holding a 1. Look at Table 2.A now. The 
CONVERSION VALUE for for COMPARTMENT LOCATION 2 is 4. 
Returning to Table 2.B we then put that 4 into the CONVERSION 
SUMMATION column. 

Why is there a 32 in Table 2.B's CONVERSION SUMMATION column? 
If your answer is "because BIT COMPARTMENT LOCATION 5 holds a 
1" you are CORRECT! 

Traditionally the arrangement of the BIT COMPARTMENTS are presented 
horizontally and not vertically. For the remainder of this book we will 
follow the following convention: 


COMPARTMENT 

LOCATION 

7 

6 5 4 3 2 1 0 

COMPARTMENT 

VALUE 

1 

1111111= 255 


34 











Abacus Software 


Atari ST MIDI Book 


The BIT COMPARTMENT LOCATION on the RIGHT is 0. It will always 
be presented as 0. As you move left the COMPARTMENT LOCATIONS 
will increment. The = 255 represents the summation of all the DECIMAL 
CONVERSION VALUES. 

Let's try another example. Using Table 2.A can you understand the 
following BIT to BYTE conversion? 


BIT # 
7 6 

5 

4 

3 

2 

1 

0 

0 0 

0 

0 

0 

0 

1 

1 = 3 


It will not be necessary to fully understand the process of BIT to BYTE 
conversion to understand the MIDI LANGUAGE. For those musicians who 
didn't have any knowledge of the hows and whys of bits and bytes we have 
presented this very brief explanation to enrich our discussion of the MIDI 
LANGUAGE. 

One other note: for the remainder of this chapter we will use DECIMAL 
numbers to explain the MIDI language, as it is most commonly understood. 
In later chapters containing the 'C' source code we will use both 
hexadecimal and decimal notation. It is not within the scope of this Atari ST 
and MIDI book to explain all of the ins and out of binary to decimal to 
hexidecimal to octal conversions, and we refer interested readers to basic 
'C language programming texts. 


35 





Abacus Software 


Atari ST MIDI Book 


2.2 Data FORMAT 


It is germane at this time to discuss the types of messages which can 
transpire between MIDI electronic instruments. For purposes of this 
discussion we will say that there are two main catagories of MESSAGE 
TYPES. They are called: CHANNEL and SYSTEM. 

The CHANNEL MESSAGE TYPE may be further divided by function into 
two more categories. They are called: VOICE and MODE. 

The VOICE MESSAGE TYPE contains information such as "Turn a note 
on in channel "Turn a note off in channel...", etc. The full list of 
VOICE MESSAGES will be presented shortly. 

The MODE MESSAGE TYPE contains information which SELECTS the 
BASIC CHANNEL (at this time thinking of it as a foundation CHANNEL 
will suffice) synthesizer MODE (see previous discussion on MODES if 
confused). 

Within the category of SYSTEM MESSAGE TYPES there are three 
sub-categories. They are called: COMMON, REAL-TIME, and 
EXCLUSIVE. 

SYSTEM'S COMMON MESSAGE TYPES may be understood and 
implemented by all MIDI synthesizer instruments hooked up to your Atari 
ST. They might include turning notes on, turning notes off, etc. 

REAL-TIME MESSAGE TYPES are used for MIDI electronic instrument 
hook-ups more complicated than, say, hooking your Atari ST to an 
electronic keyboard synthesizer. An example of where a REAL-TIME 
MESSAGE TYPE would be necessary would be if you were going to hook 
up a MIDI electronic DRUM MACHINE and a MIDI electronic keyboard 
synthesizer to your Atari ST. Your electronic DRUM MACHINE’S timing 
must be synchronized to the playing of your electronic MIDI keyboard. If 
the electronic DRUM MACHINE is not synchronized with the electronic 
keyboard then you would have some unwanted creative cacophony. 
REAL-TIME messages would allow you to synchronize the timing between 
your Atari ST, MIDI electronic keyboard synthesizer, and MIDI electronic 
DRUM MACHINE. 


36 



Abacus Software 


Atari ST MIDI Book 


SYSTEM'S EXCLUSIVE messages are specifically designed to be read and 
interpreted by your specific brand of electronic keyboard synthesizer. For 
example, PATCHES (see discussion on PATCHES in Chapter 1) may be 
sent from your Atari ST to your specific brand of synthesizer using a 
SYSTEM'S EXCLUSIVE call. Each MIDI manufacturer has what is called 
a MIDI ID code. This manufacturer ID code must be packaged in your 
SYSTEM'S EXCLUSIVE message in order for your electronic keyboard 
synthesizer to know that the following SYSTEM'S EXCLUSIVE is meant 
especially for its ears. An example of programming your Atari ST to send a 
SYSTEM'S EXCLUSIVE message will be given in Chapter III. 

We must now return to defining terms. We will call the numbers that are 
sent from your Atari ST to your keyboard synthesizer MIDI MESSAGES. 
These message numbers will be called DATA. There are two MIDI DATA 
TYPES .They are called: STATUS BYTES and DATA BYTES. 

The STATUS BYTE tells the electronic synthesizer, "Use the following 
information in this way!". A specific use of the STATUS BYTE would be 
to send the following message: 

1) Turn a note on using the instrument voice assigned to channel 1. 

Often after a STATUS BYTE is sent from your Atari ST to your MIDI 
synthesizer, one or two DATA BYTES are sent. The DATA BYTE defines 
the content of the message. Continuing the specific use of the above 
mentioned STATUS BYTE we will add the content messages of two DATA 
BYTES. 

2) The note to be turned on is middle 'C\ 

3) Turn the note on with a velocity of 64. 

You can see that the STATUS BYTE of a NOTE ON message is composed 
of a three byte sequence. The NOTE ON STATUS BYTE, the NOTE and 
the VELOCITY can be represented by three numbers. If these three specific 
numbers are sent from your Atari ST's MIDI port to the keyboard 
synthesizer the note MIDDLE 'C' will play. 

What follows will be the standard MIDI 1.0 Detailed Specifications and 
consequent tables. There are certain features of the Specification which are 
not relevant to the demonstration programs included in this book or 
appropriate for the beginner with MIDI. We have decided to gloss over 
these aspects of the Specification with the purpose of deepening the 
explanations of more relevant topics. 


37 



Abacus Software 


Atari ST MIDI Book 


Table 2.C 

SUMMARY OF STATUS 

BYTES 

STATUS # of DATA 

DESCRIPTION 

BYTES 


Channel Voice Messages 

bit # 


76543210 


lOOOnnnn 2 

Note Off event 

lOOlnnnn 2 

Note on event(vel.=0:note off) 

lOlOnnnn 2 

Poly key pressure/after touch 

lOllnnnn 2 

Control change 

llOOnnnn 1 

Program change 

HOlnnnn 1 

Channel pressure/after touch 

lllOnnnn 2 

Pitch bend change 

Channel Mode Messages 

bit # 


76543210 


lOllnnnn 2 

Selects channel mode 

System Messages 

bit # 


76543210 


1111000 ***** 

System Exclusive 

llllOsss 0 to 2 

System Common 

lllllttt 0 

System Real Time 


38 













Abacus Software 


Atari ST MIDI Book 


We'll begin our explanation by exploring the meaning of voice messages. 
Row 1 reads: 

lOOOnnnn 2 Note off event 

The "lOOOnnnn" is a binary representation (see 2.1 if you're confused by 
the binary representation) of the STATUS BYTE. A characteristic of a 
STATUS BYTE is that it will always be EQUAL TO or GREATER THAN 
128. The "nnnn" part of the binary representation refers to a channel 
number. Channels are numbered from 1 to 16 on your synthesizer, but 
internally you need to subtract 1 from the standard channel listing when 
calculating your "nnnn". The binary representation for the NOTE OFF 
EVENT has a 1 in the BIT COMPARTMENT LOCATION 7. By glancing 
at Table 2.A you can see that the decimal equivalent for a note off event is 
128 + the value of the decimal equivalent of nnnn - 1. Fortunately , the 'C' 
programming language has a very simple method of expressing the 
mathematical relationship described in the last sentence. The STATUS 
BYTE required to turn off a note is equal to: 

128 + (channel -1) 

That's not too bad. The decimal number following the binary representation 
of the STATUS BYTE tells how many DATA BYTES follow the STATUS 
BYTE. Table 2.D is an abridged version of Table 2.C with the binary 
representations of the STATUS BYTES converted into decimal form. 


Table 2.D 

STATUS 



COMMENTS 

128 

+ 

(channel 

# - 1) 

Note off 

144 

+ 

(channel 

# - 1) 

Note on 

160 

+ 

(channel 

# - 1) 

Poly key press. 

176 

+ 

(channel 

# - 1) 

Control change 

192 

+ 

(channel 

# - 1) 

Program change 

208 

+ 

(channel 

# - 1) 

Chan. press. 

224 

+ 

(channel 

# - 1) 

Pitch bend 


39 






Abacus Software 


Atari ST MIDI Book 


The SYSTEM EXCLUSIVE call is decimal 240 followed by other DATA 
BYTES. An example 'C' source code for programming the Atari ST for a 
SYSTEM EXCLUSIVE call for the Casio CZ-101 will be given in Chapter 
HI. Musical NOTES are passed from the Atari ST to your synthesizer in the 
form of DATA BYTES which are composed of numbers ranging from 0 to 
127. The relationship between the actual musical notes and the number 
scale is represented in Table 2.E 


Table 2.E 


Note 60 = middle C of keyboard 

0 12 24 36 48 60 72 84 96 108 120 127 


cccccc c c 
I-piano range- | 


The Controllers are used to control a variety of electronic synthesizer 
operations. Some of these operations are specific to individual electronic 
synthesizers while others are standards agreed upon by manufacturers. 
Table 2.F reflects the mutually accepted standard Controller numbers. 


40 








Abacus Software 


Atari ST MIDI Book 


Table 2.F 


STANDARD CONTROLLER VALUES 


CONTROL NUMBER 

CONTROL FUNCTION 

0 

1 

2 

3 

4 

5 

6 

7 

8 to 31 

32 to 63 

64 

65 

66 

67 

68 to 95 

96 

97 

98 to 121 

Undefined 

Modulation wheel or lever 
Breath Controller 

Undefined 

Foot Controller 

Portamento time 

Data Entry 

Main Volume 

Undefined 

LSB for values 0 to 31 
Damper pedal (sustain) 
Portamento 

Sustenuto 

Soft pedal 

Undefined 

Data increment 

Data decrement 

Undefined 


41 





Abacus Software 


Atari ST MIDI Book 



Table 2 

.G 


cccccccc 

Description 


0 

Continuous 

Controller 0 

MSB 

1 

Continuous 

Controller 1 

MSB (MOD BENDER) 

2 

Continuous 

Controller 2 

MSB 

3 

Continuous 

Controller 3 

MSB 

4-31 

Controller 

4-31 MSB 


3 2 

Continuous 

Controller 0 

LSB 

3 3 

Continuous 

Controller 1 

LSB (MOD BENDER) 

3 4 

Continuous 

Controller 2 

LSB 

3 5 

Continuous 

Controller 3 

LSB 

36-63 

Continuous 

Controllers 

4-31 LSB 

64-95 

96-121 

Switches(ON/OFF) 
Undefined 


122-127 

Reserved for Channel Mode messages 


Controllers can receive values ranging from 0 to 127 as demonstrated 
by Table 2.H. 



Table 2.H 





For Controllers 

0 - - - 

1 

_ _ _ 

. 



127 

i 

1 

min 





1 

max 


Switches are read as ON/OFF toggles with the value of 0 meaning OFF and 
the value of 127 meaning ON. 


42 









Abacus Software 


Atari ST MIDI Book 


Table 2.1 

For Switches 

0 - - - 

_ _ _ 

_ 

— 

- 

127 

- | 

1 

off 





on 


Table 2 J outlines the functions of the CHANNEL MODE MESSAGES. 

Numbers 123 to 127 function in such a way as to turn ALL NOTES OFF. 
These numbered messages should not be used in lieu of regular NOTE OFF 
commands. Also these ALL NOTE OFF functions will turn off all voices 
controlled by the assigned BASIC CHANNEL. One other point 
concerning CHANNEL MODE MESSAGES is that the third "MONO” byte 
designates the number of channels in which monophonic voice messages 
are to be sent. The variable "M" is a number between 1 and 16. The 
channels in operation will be the current BASIC CHANNEL (which = N) 
through channel (N + M - 1), with 16 as its maximum. Where the special 
case of M = 0 appears, this causes the synthesizer to assign all its voices to 
one per channel, ranging from the BASIC CHANNEL N through 16. 


43 






Abacus Software 


Atari ST MIDI Book 



Table 2.J 

STATUS 

DATA BYTES DESCRIPTION 

lOllnnn 

Occccccc Mode Messages 

Ovvvwvv ccccccc=122 -.Local Control 

vvwvvv=0: Loc. Control Off 
vvwvvv=127 : Loc. Control On 

ccccccc=123:All Notes Off 
vvvwvv=0 

ccccccc=124:ONMI Off(notes off) 
vvwvvv=0 

ccccccc=125:OMNI ON(notes off) 
vvwvvv=0 

cccccc=126:MONO ON (Poly OFF) 

(ALL NOTES OFF) 

vvvvvvv=M, where M = # channels 
vvwvvv=0, the number of channels 
equals the number of 
voices in the receiver 

ccccccc=127:POLY ON(MONO OFF) 
vvvvvw=0 :ALL NOTES OFF 


Table 2.K holds the information for SYSTEM COMMON MESSAGES. 
The SONG POINTER message, SONG SELECT message and TUNE 
REQUEST message are used for advanced MIDI applications. In the 
following paragraphs we will simply define their function as per the MIDI 
1.0 SPECIFICATION document. 

Inside your electronic MIDI keyboard there is an internal MIDI CLOCK. 
The value of this clock is normally set to 0 as the START switch is pressed. 
The SONG POINTER holds the MIDI BEATS. A MIDI BEAT is equal to 
six MIDI CLOCK CYCLES. The value of the SONG POINTER is 
returned to 0 if the STOP button is pressed. 


44 






Abacus Software 


Atari ST MIDI Book 


The SONG SELECT message specifies which song or sequence of songs is 
to be played upon receipt of a START (Real TIME MESSAGE). 

The TUNE REQUEST is used with ANALOG SYNTHESIZERS to request 
them to tune their oscillators. 

The EOX, or "End of System Exclusive" message is used to tell the 
electronic synthesizer that the SYSTEM EXCLUSIVE call has ended and 
the bytes subsequently following the EOX message can be handled in a 
MIDI standard (across instrument) fashion. 



Table 2 

.K 


SYSTEM COMMON MESSAGES 



STATUS 

DATA BYTES 

Description 


11110001 


Undefined 


11110010 

ON 1 1 1 II 

Ohhhhhhh 

Song Pointer 

1 1 1 1 11 1 (least 
hhhhhhh(most 

Position 

significant) 

significant) 

11110011 

Osssssss 

Song Select 
sssssss:Song 

# 

11110100 


Undefined 


11110101 


Undefined 


11110110 

none 

Tune Request 


11110111 

none 

EOX:"End of SYS EXC" flag 


SYSTEM REAL TIME MESSAGES are used for advanced MIDI 
applications. Once again, we will define the messages as they are outlined in 
the MIDI 1.0 SPECIFICATION DOCUMENT, but will omit detailed 
explanations as these messages are not used with our demonstration 
programs. 


45 





Abacus Software 


Atari ST MIDI Book 


SYSTEM REAL TIME MESSAGES are used for synchronizing all of the 
system in real time. These one- or two-byte messages may be sent to the 
MIDI synthesizer at any time. 

The TIMING CLOCK synchronizes the system, with approximately 24 
clocks per quarter note. 

The START (from the beginning of the song) byte is immediately sent when 
the master PLAY switch is pressed (on, say, the sequencer or the rhythm 
unit). 

The CONTINUE MESSAGE will tell the sequence to begin at the beginning 
of the next clock. 

The STOP MESSAGE will stop the playing sequence. 

Use of the ACTIVE SENSING MESSAGE is optional for all MIDI 
instruments. This is a "dummy" status byte which is sent every 300 ms., 
whenever there is no other activity taking place. The electronic MIDI 
instrument will operate normally if it never receives the ACTIVE SENSING 
MESSAGE. If the 300 ms. time period passes with no MIDI activity then 
the ACTIVE SENSING MESSAGE will be sent to the electronic MIDI 
instrument. The receipt of the ACTIVE SENSING MESSAGE will turn off 
all the instrument's voices and return the electronic MIDI instrument to 
normal operation. 

The SYSTEM RESET MESSAGE will initialize the electronic MIDI 
instrument to the condition right after the main electric power to the 
instrument had been turned on. The SYSTEM RESET should be used very 
sparingly as it will wipe out all of the new MIDI related information which 
you have transmitted to the electronic MIDI keyboard. 


46 



Abacus Software 


Atari ST MIDI Book 


Table 2.L 

SYSTEM REAL TIME MESSAGES 

STATUS 

DATA BYTES Description 

11111000 

Timing Clock 

11111001 

Undefined 

11111010 

Start 

11111011 

Continue 

11111100 

Stop 

11111101 

Undefined 

11111110 

Active Sensing 

11111111 

System Reset 


The SYSTEM EXCLUSIVE MESSAGES are used to tell the electronic 
synthesizer to perform an operation which is SPECIFIC to that individual 
synthesizer. A SYSTEM EXCLUSIVE CALL for, say, the Casio CZ-101, 
will NOT work with a ROLAND synthesizer. 

The SYSTEM EXCLUSIVE MESSAGE may be used to change the 
SOUND DATA for an instrument voice. For example, if you had 
programmed internal voice 1 to sound like a bamboo flute, you would need 
to use the SYSTEM EXCLUSIVE MESSAGE to change the sound of the 
bamboo flute to an electronic guitar. 

The specific byte sequences for SYSTEM EXCLUSIVE MESSAGES is 
published by the individual electronic MIDI instrument manufacturer. You 
would need to write the manufacturer of your electronic MIDI instrument 
and request the SYSTEM EXCLUSIVE information in order to obtain it. 

Table 2.M starts with the BULK DUMP. The BULK DUMP ETC. 
message tells the MIDI keyboard that a MIDI EXCLUSIVE byte stream will 
be forthcoming. 

The identification number refers to the specific ID the manufacturer received 
when they agreed to manufacture their products conforming to the MIDI 
STANDARD. 

The number of bytes sent will vary according to the nature of the 
EXCLUSIVE call. 


47 





Abacus Software 


Atari ST MIDI Book 


The EOX MESSAGE tells the MIDI synthesizer that there will be no more 
instrument specific information coming to it and it should expect MIDI 
(cross instrument brand) information in the future. 




Table 2.M 

STATUS 

DATA BYTES 

DESCRIPTION 

11110000 


BULK DUMP ETC. 


Oiiiiiii 

ID number (can be 1 to 127) 


(0*******) 

The number of bytes sent 
here will be determined 
by the nature of the system 
exclusive call. Note that 

BIT COMPARTMENT 7 will 
always contain a 0 for the 


• 

BULK DATA dumped. 


11110111 

EOX: "End of System Exclusive" 


Table 2.N shows the late 1985 list of SYSTEM EXCLUSIVE 
MANUFACTURER’S ID NUMBERS. 


48 






Abacus Software 


Atari ST MIDI Book 


Table 2.N 


SYSTEM EXCLUSIVE MANUFACTURER 

ID NUMBERS 

NUMBERMANUFACTURER 



1 

Sequential 

32 

Bon Tempi (Italy) 

2 

Big Briar 

33 

SIEL (Italy) 

3 

Octave-Platuea 

34 

IRCAM (France) 

4 

Moog 

35 

Synthax (UK) 

5 

Passport Designs 

36 

Hohner (Germany) 

6 

Lexicon 

37 

Crumar (Italy) 

7 

Kurzweil 

38 

Solton 

8 

Fender 

39 

Jellinghaus MS 

9 

Gulbransen 

40 

CTS 

1 0 

Delta Lab Research 

41 

PPG 

1 1 

Sound Compositions Systems 

42 

Elka 

1 2 

General Electro Music 



1 3 

Techmar 

64 

Kawai 

1 4 

Matthews Research & Development 

65 

Roland 

1 5 

Ensonique 

66 

Korg 

6 

Oberheim 

67 

Yamaha 

1 7 

PAiA Electronics 

68 

Casio 

1 8 

Simmons Group Centre (UK) 

69 

Akai 

1 9 

Gentle Electric 



2 0 

Fairlight (Australia) 



2 1 

JL Cooper 



2 2 

Lowery 



2 3 

Linn 



2 4 

Emu Systems 




In summary, Chapter II concentrated on explaining the MIDI LANGUAGE. 
The MIDI LANGUAGE'S vocabulary is composed of numbers ranging 
from 0 to 255. The MIDI interface in the Atari ST empowers the Atari ST 
programmer with the ability to send the MIDI vocabulary from the ST to an 
electronic keyboard synthesizer. This situation allows the Atari ST to play 
songs using a veritable cornucopia of effects permitted by the electronic 
keyboard synthesizer. In one sense, the Atari ST's internal MIDI interface 
has permitted it to be transformed into a simulated human's hands dancing 
about the keyboard. 


49 






















* 

































































Chapter III 


Programming Your Atari ST 


























Abacus Software 


Atari ST MIDI Book 


Programming Your Atari ST 


Finally we have arrived at the chapter where we will begin our explanation 
of the coding techniques we use to speak the MIDI language. But first, for 
the uninitiated, it would be wise to discuss hexadecimal notation. If you are 
familiar with hexadecimal notation, then GOTO 3.2. 


3.1 Hexadecimal Notation 


Earlier in the book we discussed how decimal numbers may be represented 
using binary notation. This was an important bit of information to learn 
because the MIDI SPECIFICATION DOCUMENT 1.0 extensively uses 
binary representation. Understanding hexadecimal notation is important 
because much of our code uses hexadecimal notation and it will definately 
be clearer to you if you are conversant with hex. 

Hexadecimal notation is not the only notation you might need on the Atari. 
Why? The answer lies in the General Instrument sound chip manual which 
uses OCTAL notation! Fortunately, we converted much of the OCTAL 
numbers contained in the General Instrument's sound chip manual into 
hexadecimal. The information is contained in the 'mdrive.c' file printed 
in Chapter 4. 

What follows is Table 3.a which will show the relationship between decimal 
numbers 0 to 16 and their hexadecimal equivalent. 


53 



Abacus Software 


Atari ST MIDI Book 


Table 

3. a 

Decimal 

Hexadecimal 

0 

0 

1 

1 

2 

2 

3 

3 

4 

4 

5 

5 

6 

6 

7 

7 

8 

8 

9 

9 

10 

a 

11 

b 

12 

c 

13 

d 

14 

e 

15 

f 

16 

10 


It is standard in the 'C' programming language to indicate that a number is 
hexadecimal by having an "Ox" precede it. For example, the number 0x0b 
would be Ob hexadecimal, and referring to Table 3.a we see that Ob is equal 
to decimal 11. For the purposes of this book, we will describe the 
conversion procedure for hexadecimal numbers of up to three digits. 


54 






Abacus Software 


Atari ST MIDI Book 


-1 

Table 3.b Hexadecimal to Decimal Conversion 


Hexadecimal Number 


0 x 0 2 b 8 


Digit 

Operation 


Result 

0 

0 x 4096 


+000 

2 

2 x 256 

= 

+512 

b 

11 x 1 

= 

+17 6 

8 

8x1 

= 

+008 




696 


Hexadecimal to Decimal 
0x02b8 = 696 


We can see from Table 3.b that the conversion process follows a logical 
format. Starting with the RIGHT digit, add it to 16 times the next left digit, 
and add it to 16 x 16 times the next left digit, and add it to 16x 16x 16 
times the next left digit Phew. 

Fortunately, the time-consuming conversion process may be bypassed by a 
shortcut which we use all the time. We own Sharp EL-515 scientific 
calculators. They have very useful binary, octal, hexadecimal and decimal 
conversion routines built in. The Sharp EL-515 sells for approximately $20 
U.S. and is routinely sold by electronic discount stores. If you ever 
program in any language this calculator will save you a ton of time. If 
you're doing any work involving the redefining of characters or reading 
charts such as the General Instrument octal representation of the Atari ST 
sound chip's parameters it will prove an indispensable time saver. 


55 











Abacus Software 


Atari ST MIDI Book 


3.2 The Extended BIOS 


There are two convenient ways to write to the MIDI ports on the Atari ST 
computer using the extended BIOS call 'midiws' and BIOS call 
'be on out'. We use the BIOS call 'be on out'. The reasons are 
simple.We use 'bconout' for many different functions in our programs 
and it has always performed flawlessly. We subscribe to the philosophy, 
"If something ain't broken and be workin' fine, DON'T FIX IT!" Enough 
said. 

The BIOS call bconout may be called from 'C' in the following fashion: 

Bconout ( device, number ) 

Device and number would both be declared as integers. The integer must be 
a 16 bit number. Please check your 'C' compiler to see how many bits are 
assigned to the int declaration. For example, the current version of Lattice 
'C' assigns 32 bits to the 'int' declaration and the programmer needs to 
substitute a 'short' instead of an 'int' in the declaration. Bconout is a 
very useful call because it does not limit you to sending information to the 
MIDI. Table 3.c describes bconout 's output parameters. 


Table 

3.c Bconout 

Parameter Device 

Device 

Output 

Device 

Number 



0 

PRT 

Centronics Interface 

1 

AUX 

RS 232 Interface 

2 

CON 

Screen 

3 

MIDI 

MIDI Interface 

4 

IKBD 

Intelligent Keyboard 


If you wish to send the number 128 through your MIDI port to your MIDI 
synthesizer, the process is a breeze in 'C'. The following few lines will do 
the trick: 


56 






Abacus Software 


Atari ST MIDI Book 


/* 

** declare integer variables 
*/ 


int number, device; 


/* 

** any number between -32767 and +32767 
*/ 


number = 128; 


/* 

** 3 = MIDI...see Table 3.c 

*/ 

Bconout( device, number ); 


The call 'Bconout ( device, number ) ;' will send 128 decimal out 
the MIDI OUT port. 

If you wish to receive information from your electronic MIDI keyboard you 
would use the Bconin BIOS function. The device numbers match those 
presented in Table 3.c. 

/* 

** declare two integer variables 
*/ 


int device, number; 


/* 

** set device =3 ... MIDI 
*/ 


device =3; 


57 



Abacus Software 


Atari ST MIDI Book 


/* 

** the value returned from the MIDI 
** will be placed in number 
*/ 


number = Bconin( device ) ; 


The program that follows will demonstrate a call to a Casio CZ series 
synthesizer which will play a chromatic scale of notes using sixteen 
different instrument voices. If you remember, an octave is a distance 
between two pitches composed of 12 gradations of sound called half-tones. 
An octave is composed of 12 half-tones. ' scaler. c ''s play will range 
through 4 octaves or 48 half-tones up and down. This call will demonstrate 
the use of both the Bconout and the Bconin BIOS function. 


58 



Abacus Software 


Atari ST MIDI Book 


3.3 scaler, c source file 


Section 3.3 is devoted to writing note data to the to the electronic keyboard 
synthesizer. This short program has many instructive routines which you 
may apply to your own programs. 


/* 

** scaler.c 
** 

** This program will play a 4 octave 
** chromatic scale using 16 different 
** instrument voices. 

** 

** This version was compiled using 
** Megamax ’C’. If you have 
** Lattice 'C* you will need 
** to change all the ’ints* to ’shorts'. 

*/ 

/* 

** include definition files here 
*/ 

♦include <osbind.h> 

♦include <stdio.h> 

/* 

** global variables and arrays 
** required for gem initialization 
*/ 

int intin [ 256 ], intout [ 256 ] , ptsin[ 256 ]; 
intptsout[ 256 ], contrl[ 12 ]; 
int handle, dummy; 

/* 

** initialize gem 

** 1) prepare intin array 

** 2) get handle using ’graf_handle...’ 

** 3) open virtual workstation 
*/ 


59 



Abacus Software 


Atari ST MIDI Book 


init__gem () 
int i ; 

for( i = 0; i < 10; i++ ) 
intin[ i ] = 1; 
intin[ 10 ] = 2; 

handle = graf_handle( &dummy, &dummy, &dummy, &dummy ); 
v_opnvwk( intin, &handle, intout ); 

} 

/* 

** Short delay 

** There are two nested loops. 

** Note the 'd2 = d2 1 statement. We 

** included this statement because Megamax wouldn't 

** compile without it. This 

** delay could easily be modified 

** to allow you to control the length 

** by passing variables which 

** would replace the loop 

** terminating conditions of 

** 1000 & 10. Do you see how? 

*/ 

delay() 

{ 

int dl, 62 ; 

for( dl = 0; dl < 1000; dl++ ) { 
for( d2 = 0; d2 < 10; d2++ ) 
d2 = d2; 

} 

} 


/* 

** This function will turn a MIDI 
** note on. Using the MIDI 
** LANGUAGE and information 
** described earlier we see 
** that the following sequence of 
** bytes must be sent to the MIDI 
** in order to turn a note on. 

★ -k 


60 



Abacus Software 


Atari ST MIDI Book 


** 1) (128 + 16 + 0 ) -> status for note 

** on in channel 0 

** 2) data byte containing 
** note number (36 - 96) 

** 3) velocity (0 to 128) 

** The Bconout bios call is 
** used to send data to the 
** MIDI. The '3' parameter is 
** the device number for MIDI. 

** The 'note_on' function may 
** be transported to your own 
** programs with ease. 

*/ 

note_on( channel, n_number, velocity ) 
int channel, n_number, velocity; 

{ 

Bconout( 3, (128+16+channel) ); 

Bconout ( 3, n_number ); 

Bconout( 3, velocity ); 

} 


/* 

** This function will turn a MIDI 
** note of. The following sequence of 
** bytes must be sent to the MIDI 
** in order to turn a note off. 

** 

** 1) (128 + 0 ) -> status for note 

** of in channel 0 

** 2) data byte containing 
** note number (36 - 96) 

** 3) velocity (0 to 128) 

** As with the 'note_on' function 
** 'note_off’ may be easily 
** used in your own programs. 

*/ 

note_off( o_channel, o_n_number, o_velocity ) 
int o_channel, o_n_number, o_velocity; 

{ 

Bconout( 3, (128+o_channel) ); 


61 



Abacus Software 


Atari ST MIDI Book 


Bconout( 3, o_n_number ); 
Bconout( 3, o_velocity ); 


/* 

** This is the main code 
** The first function called is 
** 1 appl_init() 1 . It is 
** used to get an application 
** id number. We include it 
** here because our programs 
** have no problems initializing 
** gem. Although gem, once you 
** get your feet wet with the 
** bindings, is a real time 
** saver. One discomfort we 
** experience using gem, is that 
** we are using code other 
** programmers have written. 

** Remember to include the 
** 'appl_init() 1 call before 

** you open the virtual workstation. 
** When we forgot, we were reminded 
** of our indiscretion with a 
** 1 shroom display! 

*/ 


main () 

{ 

int c ; 

int program, note_val; 
/* 

** GEM initialization 
*/ 


appl_init (); 

init_gem(); /* initialize gem */ 
v clrwk( handle ); /* clear screen */ 


62 



Abacus Software 


Atari ST MIDI Book 


/* 

** begin introduction 
*/ 


printf("MIDI Chromatic Scale Demonstration \n") ; 
printf("by Len Dorfman and Dennis Young \n\n"); 
printf("Press MONO button on Casio CZ synthesizer\n"); 
printf("and then RETURN key to begin. \n "); 

c = getcharO; /* megamax waits for return to exit 

’getchar()’, Alycon needs a Control z */ 


/* 

** This outside ’for 1 loop changes the 
** instrument voice using the MIDI 
** LANGUAGE ’PROGRAM CHANGE’ message. 
** The status byte for the program 
** change has bits 7 & 6 on. Bits 
**0-3 are used for the channel 
** number. 

*/ 


for( program = 16; program < 32; program++ ) { 

printf("\nChromatic scale using Instrument voice # %d. 
\n", program); 

Bconout( 3, (128+64+0) ); 

Bconout( 3, program ); 


/* 

** These nested loops will take all the 
** note values ranging from 36 to 95 and 
** play them in an ascending fashion, and 
** then a descending fashion. This rise 
** and fall of pitch will occur for each 
** instrument voice selected by the 
** outer loop. 

** 1) set looping condition for note rise 
** 2) turn note on using value in ’note_val’ 
** 3) A short delay is called so the 
** notes may be heard (’C’ on a 68000 

** will prove fast in a human time frame ) 

** 4) the note is then turned off 
*/ 


63 



Abacus Software 


Atari ST MIDI Book 


for( note_val = 36; note_val < 96; ++note_val ) { 

note_on( 0, note_val, 64 ); 
delay(); 

note_off( 0, note_val, 64 ); 

} 

/* 

** Note the 1 —note_val': why did we use it instead 
** of 1 note_val— 1 ? The answer is that there is 
** a bug in the version of megamax we are using 
** which will not implement a 'variable— f . The 
** bug is now known and I'm sure will be fixed 
** by the time you read this. Megamax is currently 
** our favorite 'C* compiler. The Atari 20 meg. 

** hard drive and Megamax are a combination made 
** in heaven. 

*/ 

for( note_val = 96; note_val > 35; —note_val ) { 

note_on ( 0, note_val, 64 ); 
delay(); 

note_off ( 0 r note_val, 64 ); 

} 

} 

/* 

** The 1 appl_exit () ’ call allows us to 
** return to an unblemished desktop 
*/ 

appl_exit () ; 

} 

/* 

** end of 1 scaler.c* 

*/ 


64 



Abacus Software 


Atari ST MIDI Book 


You can change the speed of program execution by changing the values in 
the delay function. Lower numbers translate into a shorter delay, and that 
translates into faster play. The music player in 'mdrive.c' (presented in 
Chapter IV) is just a simple embellishment of ' scaler. c'. 


Section 3.4 of Chapter IE will demonstrate how you can read the keyboard 
synthesizer's keyboard, and capture the note on/off information with your 
Atari ST. 


65 



Abacus Software 


Atari ST MIDI Book 


3.4 readkey.c source code 


This chapter contains the Dorfman/Young challenge. Our MIDI-oriented 
music composition ST MUSIC BOX lacks a feature which certain MIDI 
aficionados would be interested in having: Real Time Capture. This MIDI 
buzz phrase basically means that the software running on your Atari ST 
would have the ability to record what songs are being played on the MIDI 
keyboard synthesizer and later play them back. Our reasons for not coding 
the Real Time Capture option on the initial version of ST MUSIC BOX as 
explained elsewhere in the book, had nothing to do with the technical 
complexity of the programming assignment or the equipment. By not 
programming a Real Time Capture option on our ST MUSIC BOX disk, we 
have left the avenue open for YOU to write the program. 

The source file 'readkey. c' is a short demo file which shows you how to 
read the MIDI keyboard and print the information to the screen. You can 
modify this code so that the information which is currently directed to the 
screen could be channeled into buffers—for future playing. A VERY 
SIMPLE algorithm for a Real Time Capture program might look something 
like this: 


Capture of Note data 


/ 1) Read all the MIDI input 4 

i - 1 



2) Have a programmer written 
clock keep time and store 
the MIDI input and TIME 
information in a buffer. 

n 



3) Wait a TIME increment 



66 














Abacus Software 


Atari ST MIDI Book 


Playback NOTE data 


n 

Get note ON and note .y* 

OFF information. / 

\ 

2) 

Turn ON and OFF the 
proper instrument 
voices. 

1 

3) 

Wait till next TIME 
interval. 




If you decided to be really ambitious, then you might look at the 
'interf. c' file presented in Chapter IV and convert the Real Time 
Capture information into a file structure which would be compatible with the 
AUTO-PLAYER program presented in this volume. 

Before we move on to the source code for 'readkey. c' we will discuss 
the nature of the information which will be presented on the screen. If you 
were running the program and you pressed the MIDDLE 'C' key on the 
Casio CZ-101 keyboard synthesizer, you would see the following message 
printed to your video display: 


MIDI transmitted 144 
MIDI transmitted 60 
MIDI transmitted 64 
MIDI transmitted 60 
MIDI transmitted 0 


Let's see if we can make some sense of the byte stream received by the Atari 
ST. We'll take them one value at a time. 


67 












Abacus Software 


Atari ST MIDI Book 


The first 144 represents the NOTE ON message. The NOTE ON message 
is composed of the following: 128 + 16 + channel number. The default 
channel for the Casio CZ-101 is 0. So, 128 +16 + 0 equals NOTE ON. 

The 60 which comes directly after the the NOTE ON (144) represents the 
note VALUE. If you examine the MIDI LANGUAGE section you'll be 
reminded that the note VALUE of 60 denotes the MIDDLE 'C'. 

The 64 which follows the first 60 represents the VELOCITY of the note. 
The Casio CZ-101 does not implement variable velocity, and all notes are 
turned on and off with a VELOCITY of 64. 

If you return to the MIDI LANGUAGE section of the book, you'll see that 
the NOTE ON message has the following format: 


Byte # VALUE Message 


1) 

128 

+ 16 + channel # 

NOTE 

ON 

2) 

0 - 

127 

NOTE 

PITCH VALUE 

3) 

0 - 

127 

NOTE 

VELOCITY* 


*Velocity = 0 -> NOTE OFF 


The first three values transmitted from the Casio CZ-101 through the MIDI 
interface are 144, 60, 64. These values are the NOTE ON message for 
MIDDLE 'C' in channel 0. 

The fourth value 60 actually appeared when you RELEASED the key. The 
60 and the 0 actually can be read as a packet of two bytes. The number 
following the NOTE PITCH VALUE, the VELOCITY, will turn an 
instrument voice OFF when it is 0. That's correct. We'll repeat it again. If 
the VELOCITY of a NOTE is 'O', whether it is sent with a NOTE ON or a 
NOTE OFF message, will turn a note OFF. 


68 





Abacus Software 


Atari ST MIDI Book 


A new status byte ( >= 128...see MIDI LANGUAGE) need not be sent as 
the status of the keyboard synthesizer had not changed. Let's review values 
sent from the MIDI one more time: 

Turn ON MIDDLE ’C’ 


MIDI transmitted 144 -> status byte for Note ON 

MIDI transmitted 60 -> note value middle 'C' 

MIDI transmitted 64 -> turn middle 'C' on velocity 64 

Turn OFF MIDDLE'C' 


MIDI transmitted 60 -> note value middle 'C' 

MIDI transmitted 0 -> velocity ’0’ means NOTE OFF 


If we were to explore the algorithm for a Real Time Capture program in a bit 
more depth, we might create the following rules for MIDI received 
information: 

1) If a received value is 144 -> (144+16) there is a NOTE ON 
message in a channel (value -144) 

2) The value directly following the NOTE ON message is a note 
PITCH value ranging from 0 to 127. 

3) The value after the PITCH value represents VELOCITY. If the 
velocity is equal to 'O' it will turn the NOTE off. 

4) The PITCH value and Velocity value will alternate until a new 
STATUS byte appears. 

To test the information presented, run the program and press the MIDDLE 
'C key, but do not release it. Look at your video display. If you are using 
a Casio CZ-101 (if you're not using a CZ-101 the VELOCITY number will 
vary) you will see: 

MIDI transmitted 144 
MIDI transmitted 60 
MIDI transmitted 64 


69 





Abacus Software 


Atari ST MIDI Book 


Release the MIDDLE 'C' key and two more bytes will be printed to the 
screen. They are: 

MIDI transmitted 60 
MIDI transmitted 0 

If you do write the Real Time Capture program it might turn into an article, 
or more. We'd love to see any MIDI-related programs you might write as a 
result of reading this text. You may send them to us at Abacus. 

On to the source code for 'readkey. c'. 


/* 

** readkey.c 
★ * 

** This file will demonstrate how 
** read keyboard data transmitted 
** from the midi synthesizer 
** to the Atari ST. It was compiled 
** and linked using Megamax C. 

*/ 

/* 

** include files here 
*/ 


♦include <osbind.h> 
♦include <stdio.h> 

/* 

* globals here 
*/ 


inti2[6], mkmx, mkmy, mkmstate, mkkstate; 
inti3[6], holdv; 

intgflag, gflagl, gflag2, toggle, ctr; 


/* 

** global variables and arrays for GEM 
*/ 


70 



Abacus Software 


Atari ST MIDI Book 


int intin[ 256 ], intout[ 256 ], ptsin[ 256 ]; 
int ptsout[ 256 ], contrlt 12 ]; 
int handle, dummy; 

/* 

** initialize gem 
*/ 

init_gem() 

t 

int i; 

for( i = 0; i < 10; i++ ) 
intint i ] = 1; 
intint 10 ] = 2; 

handle = graf_handle( Sdummy, &dummy, sdummy, 
v_opnvwk( intin, shandle, intout ); 

} 

/* 

** Short delay 
*/ 

delay () 

{ 

int dl, d2; 

for( dl = 0; dl < 1000; dl++ ) { 

for( d2 = 0; d2 < 10; d2++ ) 
d2 = d2; 

} 

} 


/* 

** get an int from the midi 
** and return it 
*/ 

from_midi() 

{ 

int ifm; 

ifm = Bconin( 3 ); 
ifm &= OxOOff; 


71 


&dummy ); 



Abacus Software 


Atari ST MIDI Book 


printf("MIDI trasnsmitted byte %d \n", ifm ); 
return( ifm ); 


/* 

** check to see if a midi byte is waiting 
** returns a 0 if no and a 1 if yes 
*/ 

midi_status() 

{ 

int ims; 

ims = Bconstat( 3 ); 
if ( ims != 0 ) 
ims =1; 
return( ims ); 


/* 

* check the status of midi out and evaluate 
*/ 

check_status() 

{ 

int flag, ret; 

flag = midi_status() ; 
switch( flag ) { 

case 0: 

gflag =1; 
break; 
default: 

ret = from_midi(); 
break; 

} 

return( ret ); 

} 


72 



Abacus Software 


Atari ST MIDI Book 


/* 

** clean out all the midi bytes 
** received from cz 101 
*/ 

clean_house() 

{ 

gflag = 0; 

while( gflag == 0 ) { 

check_status(); 

} 

} 

/* 

* wait on a key press 
*/ 

wait_key() 

{ 

char c; 

printf("\n***Waiting...Press RETURN KEY to 
continue\n\n"); 

c = getcharO; 

} 

/* 

** main program code 
*/ 

main () 

{ 

char *ch, chi; 

int il, hold, temp, *voice; 

/* 

** GEM initialization 
*/ 


appl_init(); 
init_gem(); 

v_hide_c(handle); /* hide cursor */ 
v clrwk(handle); /* clear screen */ 


73 



Abacus Software 


Atari ST MIDI Book 


/* 

** program introduction 
*/ 

printf("This program, by Len Dorfman and Dennis Young,\n"); 
printf("will read data transmitted to the Atari ST\n"); 
printf("through the MIDI ports.W); 


wait_key() ; 

printf("Bytes are transmitted from the MIDI when there\n"); 
printf("are MIDI keyboard events. If the transmitted \n") ; 
printf("information is not received by the Atari ST it\n"); 
P r; *- n tf ("will remain stored. To demonstrate how the\n") ; 
printf("MIDI transmits note information we will clean\n"); 
printf("out the MIDI of all bytes."); 
wait_key(); 

clean_house(); 


printf("The MIDI pipe is now clean and you may press\n"); 
printf("any key on the MIDI keyboard. To return to the\n”); 
printf("desktop press the CONTROL key.\n\n”); 

/* 

** We use the GEM 'graf_mkstate' call 
** to leave the MIDI read loop because 
** the program will cycle through the 
** call without stopping. Remember 
** to link the GEM libraries in your 
** compiler package in order to have 
** the program link properly. 

* ;k 

** The mkkstate is short for 'mouse 
** /keyboard state'. You can read 
** the CONTROL, ALTERNATE, LEFT SHIFT, 

** and RIGHT SHIFT keys. If any of 
** them are pressed the 'graf_mkstate' 

** call will put a non-zero value in 
** variable mkkstate. The while loop 
** will then terminate. 

*/ 


74 



Abacus Software 


Atari ST MIDI Book 


mkkstate = 0 ; 

while( mkkstate == 0 ) { 

graf_mkstate( Smkmx, &mkmy, &mkmstate, Smkkstate ); 

il = midi_status(); /*is MIDI byte waiting*/ 
if( il != 0 ) /* if YES then */ 

from_midi(); /* print the value to screen */ 

} 


v_show_c( handle, 1 ); 
appl_exit() ; 

} 

/* 

** end of readkey.c 
*/ 

Section 3.5 will present the source code for a small program which will 
demonstrate the SYSTEM EXCLUSIVE call on a Casio CZ-101 electronic 
synthesizer. 


75 



Abacus Software 


Atari ST MIDI Book 


Example Screen Display of READ KEY. PRG: 

This program written by Len Dorfman and Dennis Young, 
will read data transmitted to the ATARI ST through the 
MIDI ports. 

***Waiting...Press RETURN KEY to continue 

Bytes are transmitted from the MIDI when there are 
MIDI keyboard events. If the transmitted information 
is not recieved by the ATARI ST it will remain stored. 
To demonstrate how the MIDI transmits note information 
we will clean out the MIDI of all bytes. 

***Waiting...Press RETURN KEY to continue 


MIDI transmitted byte 0 

The MIDI pipe is now clean and you may press 
any key on the MIDI keyboard. To return to the 
desktop press the CONTROL key. 

MIDI transmitted byte 144 
MIDI transmitted byte 60 
MIDI transmitted byte 64 
MIDI transmitted byte 60 
MIDI transmitted byte 0 
MIDI transmitted byte 144 
MIDI transmitted byte 61 
MIDI transmitted byte 64 
MIDI transmitted byte 61 
MIDI transmitted byte 0 
MIDI transmitted byte 144 
MIDI transmitted byte 36 
MIDI transmitted byte 64 
MIDI transmitted byte 36 
MIDI transmitted byte 0 


76 



Abacus Software 


Atari ST MIDI Book 


3.5 patch, c source code 


The source code for ' patch. c ' is presented in this section of Chapter HI. 
The program generated by ' patch. c ' will demonstrate how to enable a 
MIDI SYSTEM EXCLUSIVE call on the Casio CZ-101 synthesizer. The 
nature of the system exclusive byte sequence is described in your 
synthesizer's MIDI SYSTEM EXCLUSIVE documentation. If the system 
exclusive documentation didn't come with your synthesizer, write the 
manufacturer. They will send you the appropriate information. 

Returning to a previously mentioned term, the PATCH is a collection of 
tone data which programs the synthesizer to sound in differing ways. 
Patches may be programmed into the synthesizer by playing with the 
appropriate buttons and dials on the synthesizer's body. 

The program ' patch . c ' will take a patch which has previously been 
programmed into the Casio CZ-101 and dump it to your screen or printer. 
You will be able to explore the patches for the Preset voices, the Internal 
voices, or ev°n Cartridge voices. 

By examining the techniques used in this program, you will be able to 
extend it so that ' patch. c ' will be able to LOAD and SAVE patches to 
and from your synthesizer. 

One other note: Even though bytes of information are sent and received 
from the Casio, the system exclusive TONE DATA are split into 1/2 byte 
statements, called ' nibbles '. We will briefly describe a 'nibble'. 


NIBBLES 

Binary Byte 

high nibble 

low 

nibble 

11110101 

1111 

0 1 

0 1 


From the little diagram you can see that bits 7, 6, 5, and 4 are transformed 
into what's called the 'high order' nibble. Bits 3, 2, 1, and 0 are combined 
into the 'low order' nibble. Nibble values range from 0 to 15. That is 


77 








Abacus Software 


Atari ST MIDI Book 


because the 'high order’ nibble is evaluated as if the bits were shifted 4 
places to the right. The 'high order' nibble would be evaluated like this: 
0000 1 1 1 1 . 

In the previous example the 'high order' nibble is 15 and the 'low order' 
nibble is 5. The Casio outputs 'low order' nibble and then the 'high order' 
nibble. 

The SYSTEM EXCLUSIVE documentation should be much, much more 
thorough than is presented here. The purpose of this code is to give Casio 
users a useful program and others a framework to develop programs which 
use SYSTEM EXCLUSIVE calls on their synthesizers. 


/* 

** patch.c - by Len Dorfman and Dennis Young 

★ ;k 

** patch.c, using MIDI exclusive calls 
** will tell the Casio Cz 101 to dump 
** its tone data to the screen 

** for preselect instrument voice 1. 

** 

** The following table describes the byte 
** handshake sequence that the Casio systems 
** exclusive call for the SEND REQUEST 1 
** message requires. (All the values 

** in the following table are HEXADECIMAL). 
** 

** Computer -> CZ 101 

★ ★ _ 

** Oxf7, 0x44, 0x00, 0x00, 0x70, 0x10, 0x10 
** 

** Cz 101 ~> Computer 
★ ★ ----- 

** Oxf0, 0x44, 0x00, 0x00, 0x70, 0x30 
** 

** Computer -> CZ 101 
** _ 

** 0x70, 0x31 

★ ★ 

** CZ 101 -> Computer 
* * - 

** **tone data**, 0xf7 


78 







Abacus Software 


Atari ST MIDI Book 


•k k 

** Computer -> CZ 101 
** - 

** 0xf7 
** 

** The previous byte sequence will 
** be more full explained in the 
** following source. 

*/ 

/* 

** include files here 
*/ 

♦include Cosbind.h> 

♦include <stdio.h> 

/* 

* globals here 
*/ 

int i2[6] ; 

int i3[6], holdv; 

int gflag, gflagl, gflag2, toggle, ctr; 


/* 

** global variables and arrays for GEM 
*/ 

int intin [ 256 ], intout [ 256 ], ptsin[ 256 ]; 
int ptsout[ 256 ], contrl[ 12 ]; 
int handle , dummy; 

/* 

** initialize gem 
*/ 

init_gem () 

{ 

int i ; 

for( i = 0; i < 10; i++ ) 
intin[ i ] = 1; 


79 




Abacus Software 


Atari ST MIDI Book 


intin[ 10 ] = 2; 

handle = graf_handle( &dummy, &dummy, &dummy, &dummy ); 
v_opnvwk( intin, Shandle, intout ); 

} 

/* 

** Short delay 
*/ 

delay() 

{ 

int dl, d2 ; 

for( dl = 0; dl < 1000; dl++ ) { 
for( d2 = 0; d2 < 10; d2++ ) 
d2 = d2; 

} 

} 

/* 

** Casio patch integer array 
*/ 

int patch[128]; 

/* 

* CASIO system exclusive data 

* element: 

* 4 is 0x70 + channel # 

* 6 is program # 

*/ 


int sendrl[8] = { 

OxfO,0x44,0x00,0x00,0x70,0x10,0x10 } ; 

/* 

** send a int to the midi 
** 

** the byte will be shown on the 
** screen in hex. format. 

*/ 


80 



Abacus Software 


Atari ST MIDI Book 


to_midi ( itm ) 
int itm; 

{ 

Bconout ( 3, itm ); 

printf("Computer transmitted byte Ox%x \n 

} 

/* 

** get an int from the midi 
** and return it in hex. format 
★ ★ 

** the bit mask OxOOff will 
** take an integer (which is 
** composed of two bytes) and 
** lop off the upper byte. 

** 

** the mask is just a safety 
** procedure—extra cautious 
*/ 

from__midi () 

{ 

int ifm; 

ifm = Bconin( 3 ) ; 
ifm &= OxOOff; 

printf("MIDI trasnsmitted byte Ox%x \n”, 
return( ifm ); 

} 


/* 

** Get an int from the midi 
** and return it to the 
** calling function. This 
** call does not print the 
** MIDI byte to the screen. 
*/ 


”, itm ); 


ifm ) ; 


81 



Abacus Software 


Atari ST MIDI Book 


p_midi() 

{ 

int ifm; 

ifm = Bconin( 3 ); 
ifm &= OxOOff; 

return( ifm ); 

} 

/* 

** check to see if a midi byte is waiting 
** returns a 0 if no and a 1 if yes 
*/ 

midi_status () 

{ 

int ims; 

ims = Bconstat( 3 ); 
if ( ims != 0 ) 
ims = 1; 
return( ims ); 

} 


/* 

* check the status of midi out and evaluate 
*/ 

check_status() 

{ 

int flag, ret; 

flag = midi_status(); 
switch( flag ) { 

case 0: 

gflag = 1; 
gflagl = 0xf7; 
break; 
default: 

ret = from_midi(); 
break; 

} 


82 



Abacus Software 


Atari ST MIDI Book 


return( ret ); 

} 


/* 

* check the status of midi out and evaluate 
*/ 

mp_status() 

{ ' 

int flag, ret; 

flag = midi_status(); 
switch( flag ) { 

case 0: 

gflag = 1; 

printf("MIDI EMPTY!!!\n"); 
break; 
default: 

ret = p_midi(); 

break; 

} 

return( ret ); 

} 

/* 

** clean out all the midi bytes 
** received from cz 101 
*/ 

clean_house() 

{ 

gflag = 0; 

while( gflag == 0 ) { 

check_status(); 

} 

} 

/* 

* wait on a key press 
*/ 


83 



Abacus Software 


Atari ST MIDI Book 


wait_key () 

{ 

char c; 

printf("\n***Waiting...Press RETURN KEY to 
continue\n\n n ); 

c = getchar(); 

} 

/* 

** Converts a digit from decimal to 
** hex. ascii. 

*/ 

conv_itoa( val ) 
int val; 

{ 

if ( val < 10 ) 

val += 48; /* hex digit to ascii */ 


else if 

( val == 

10 

) 

val = 

'a 1 ; 



else if 

( val == 

11 

) 

val = 

f b 1 ; 



else if 

( val == 

12 

) 

val = 

1 c 1 ; 



else if 

( val == 

13 

) 

val = 

'd l ; 



else if 

( val == 

14 

) 

val = 

1 e 1 ; 



else 




val = 

l f'; 



return( val ); 




} 

/* 

** This code will print the patch[] to the screen 
** or printer. 

** 1) print message 

** 2) set device=0 for printer 

** device = 2 for screen. 

** 3) convert patch[] which holds int data 

** into ascii data. 

** 4) use bios to print to screen or printer 

*/ 


84 



Abacus Software 


Atari ST MIDI Book 


char p_msg[] = "Patch for Instrument voice #" ; 

print_patch() 

{ 

int device, column, i2; 
if( toggle == 1 ) 

device =0; /* printer selected */ 

else 

device =2; /* screen selected */ 

if( device != 0 ) { 
printf("\n\n"); 
for( i2 = 0; i2 < 28; ++i2 ) 
printf("%c", p_msg[ i2 ] ); 
printf("%d", holdv); 

} 

else { 

Bconout( device, '\n' ); 
for( i2 = 0; i2 < 28; ++i2 ) 

Bconout( device, p_msg[ i2 ] ); 
holdv = conv_itoa( holdv ); 

Bconout( device, holdv ); 

} 

if( device == 0 ) 

Bconout( device, '\n' ); 
else 

printf("\n"); 

for( i2 = 0; i2 < 128; ++i2 ) 

patch[ i2 ] = conv_itoa( patch[ i2 ] ); 

/* 

** column is set for formatting the 
** output to the screen or printer 
*/ 


column = 0; 

for( i2 = 0; i2 < 128; ++i2 ) { 

Bconout ( device, patch[ i2 ] ); 
Bconout( device, ); 


85 



Abacus Software 


Atari ST MIDI Book 


++column; 

if( column > 31 ) { 
column = 0; 
if( toggle == 1 ) 

Bconout( device, '\n' ); 
else 

printf("\n"); 

} 

} 

Bconout( device, '\n' ); 

Bconout( device, '\n' ); 

} 

/* 

** main program code 
*/ 

main () 

{ 

char *ch, chi; 

int il, hold, temp, *voice; 

/* 

** Gem initialization 
*/ 

appl_init(); 
init_gem() ; 

v_hide_c(handle);/* hide cursor */ 
v_clrwk(handle); 

/* clear screen */ 


/* 

** program introduction 
*/ 

printf("This program, by Len Dorfman and Dennis Young,\n"); 
printf("will dump the tone data (patch) for a Casio CZ\n"); 
printf("101 electronic keyboard synthesizer to the\n"); 
printf("screen or printer.\n\n"); 


86 



Abacus Software 


Atari ST MIDI Book 


/* 

** query output 
*/ 

printf("Do you wish to dump to (S)creen or (P)pinter? "); 

ch = &chl; 
scant ("%c", ch) / 


/* 

** feedback for choice 
*/ 

if ( chi == 'p' || chi == 'P' ) { 

toggle = 1; /* printer */ 

printf("\nYou have selected the printer.\n M ); 

} 

else { 

toggle = 0; /* screen if not 'p' */ 

printf("\nYou have selected the screen.\n"); 

} 

printf("\n\n"); 

/* 

** the for( ;; ) is an infinite 
** for loop which will be broken 
** out of if a value between 1 
** and 96 is entered 
*/ 


for( ;; ) { 

printf("Which instrument voice (1 - 96)?"); 

voice = &il; 
scanf("%d", voice ); 

if( il >= 1 && il <= 96 ) 
break; 

} 


87 



Abacus Software 


Atari ST MIDI Book 


/* 

** feedback for choice 
*/ 

printf ("\nYou have selected instrument voice #%d.\n", il) ; 

/* 

** save instrument voice 
** selected for later 
*/ 

holdv = il; 

/* 

** decrement because internal 
** use of instrument voice goes 
** from 0-95 and not from 
** 1 to 96 

*/ 

—il; 

printf("\n"); 

printf("Make sure that your MIDI cables are connected\n"); 
printf("to your Casio and that it is turned on.\n\n"); 
printf("If you are dumping to the printer then make\n"); 
printf("sure the printer is connected and turned on.\n\n"); 
printf("The bytes from the MIDI will be remembered in a\n"); 
printf("buffer so we will clean out the MIDI read\n"); 
printf("buffer before we to dump the patch.\n"); 

wait_key(); 


/* 

** empty the MIDI buffer 
** of all bytes 
*/ 


gflag = 0; 

while( gflag == 0 ) 


88 



Abacus Software 


Atari ST MIDI Book 


{ 

check_status(); 

} 


printf("We send this byte to tell the MIDI that we will\n"); 
printf("begin tranmission of system exclusive "); 
printf("information.\n\n"); 

/* 

** for saftey 
*/ 


to_midi( 0xf7 ); /* end sys exc */ 

wait_key() ; 
printf("\n") ; 

printf("The SEND REQUEST 1 SYSTEM EXCLUSIVE MESSAGE\n"); 
printf("is composed of the following hex. bytes:\n\n"); 
printf("fO / 44 / 00 / 00 / 70 / 10 / instr. voice #.\n\n"); 
printf ("Let' s send them to the Casio.\n"); 

wait_key(); 


/* 

** you change the instrument 
** voice selected in the 
** appropriate spot in the 
** buffer which will soon 
** be sent to the MIDI 
*/ 

sendrl[ 6 ] = il; 

printf("Send Request l\n"); 
printf ("-\n") ; 

/* 

** send the MIDI system exclusive 
** from the buffer to the MIDI 
*/ 


89 




Abacus Software 


Atari ST MIDI Book 


for( il = 0; il < 7; il++ ) 
to_midi( sendrl[ il ] ); 

printf("\nThe Casio will now respond with the\n”); 

printf("following bytes:\n\n") ; 

printf ("f 0 / 44 / 00 / 00 / 70 / 30 .\n\n"); 

printf("If the MIDI transmitted bytes match those\n"); 

printf("above then the first part of the handshake\n"); 

printf("has been successfully completed. Let's\n"); 

printf ("see what bytes the MIDI has transmittedAn") ; 

wait_key () ; 


/* 

** check to see if the Casio 
** has received the bytes and 
** confirms that it has with 
** the appropriate message 
*/ 


for( il = 0; il < 6; il++ ) 

/* read midi response */ 
check_status(); 

wait_key () ; 

printf("The ST must transmit the following bytes An"); 
printf("70 / 31. These hex. bytes signify that the ST\n"); 
printf("has read the first hand shake response and is\n"); 
printf("ready to receive the patch tone data An"); 
printf("Let 1 s send the bytes.\n"); 

wait_key(); 


/* 

** more Casio protocol here 
*/ 


tojmidi ( 0x7 0 ); 
to_midi( 0x31 ); 

printf("\nNow that the 70 / 31 hex. bytes have been\n"); 
printf("transmitted to the MIDI let's get on with the "); 


90 



Abacus Software 


Atari ST MIDI Book 


printf("patch grab!\n"); 
wait_key(); 


/* 

** here is where we grab the 
** patch from the MIDI and place it in 
** the buffer called 'patch[]' 

*/ 

for(il = 0; il < 128; il++ ) 
patch [il] = mp_status(); 

/* 

** not that we have the patch safely 

** tucked away we can print it 

** to either the screen or printer 

** depending on what we had previously selected 

*/ 

print _jpatch () ; 
wait_key () ; 


/* 

** the 'bye-bye 1 Casio sign 
** off protocol 
*/ 

tojmidi( Oxf7 ) ; 

/* 

** show the cursor and clean up 
** the gem stuff for re-entry 
** to the desktop 
*/ 

v_show_c( handle , 1 ); 
appl_exit(); 

} 


91 



Abacus Software 


Atari ST MIDI Book 


/* 

** end of patch.c 
*/ 


In this chapter we have demonstrated how to send note information from the 
Atari ST to the MIDI synthesizer and how to read information from the 
MIDI synthesizer and manipulate with the Atari ST. The programs in this 
chapter functioned as our introduction to the AUTO-PLAYER. 

The program presented in Chapter IV is massive (although it is 1/3 the size 
of our ST MUSIC BOX). Onward to Chapter IV. 


92 



Chapter IV 


ST MUSIC BOX AUTO-PLAYER 










Abacus Software 


Atari ST MIDI Book 


ST MUSIC BOX AUTO-PLAYER 


This chapter will contain the full source code to the ST MUSIC BOX 
AUTO-PLAYER version 1.0, and various smatterings from the source to 
XLent Software's ST MUSIC BOX program, which we co-authored. We 
present this code in an effort to share what we have learned about 
programming on the ST, working cooperatively as a team and bringing a 
commercial program from idea to fruition. For some, this personal 
discussion may not seem germane to learning to program your Atari ST's 
MIDI port, but for others it may prove instructive reading. We always love 
to hear how other programming artists and engineers formulate their ideas 
and work; it expands our creative vision. It is with this hope that we 
recount our story in words and code. 


4.1 In the Beginning 


Once we decided to take on the MIDI programming project for XLent 
Software we decided to delve deeper into MIDI-land and see what existing 
MIDI software offered. Also we spoke with a few people about what they 
wished to see in MIDI programs. The program functions were: 

1) the ability to enter music note data using the mouse; 

2) the ability to play that data through a MIDI STANDARD DEVICE; 

3) real time keyboard note capture; 

4) the ability to dump the manuscript to a graphic printer. 

Xlent Software in concert with our current philosophy decided that writing a 
product that would come to market for under $50 U.S. would be critical to 
the program's commercial success. It seemed obvious that a $50 dollar 
program would not have the same power as a $300 program, but we were 
intent on providing a powerful package nonetheless. With that in mind we 
decided to develop a plan which would allow us to approximate how long it 
would take us to write MIDI related code. Much of the programming 
initially appeared (and subsequently proved) technically trivial, but we knew 
from our current list of eight co-authored published programs, "If 
something can 'gang aft agley', it will!" 


95 



Abacus Software 


Atari ST MIDI Book 


We decided that the main program should basically be composed of two 
elements: a smart note editor and a music player. A separate printer-only 
dedicated program would be constructed using the editor's file structure and 
be placed on ST MUSIC BOX'S main diskette. The editor and player 
should handle 8 voices, with two voices assigned to each channel. It 
seemed clever to have the player simultaneously drive the MIDI keyboard 
synthesizer and the console speaker at the same time. The focus of the 
program would be MIDI oriented, but adding the option of the console 
speaker play would just add a few bytes to what seemed like a clean and 
simple program (the final code for the ST MUSIC BOX program weighed 
in at approximately 120,000 bytes). 

We decided that the PLAYER should have an animated display. Here Len 
argued strongly for a clean-as-a-bean diagnostic-type display. No colors or 
flash. Others in the company argued that colors and flash sell, but Len stood 
stubborn ground saying, "The player must sound right and visually aid the 
composer in the sound parameter editing process. There should be nothing 
that would distract the eye." The view of the company was bom out of a 
COMDEX demonstration where some press commented that they thought 
the player might be a bit more colorful. When the people at Xlent reported 
that finding to Len he replied, "I've entered thousands of notes! Not them! 
I don't want my eyes distracted in any way. Period." And so it goes... 

To that end, the PLAYER wound up having animated shapes that danced 
horizontally as they represented the frequency of the notes being played. 
The measure being played is displayed by number, as are the 
INSTRUMENT VOICES assigned to each channel. Dennis reasoned that 
the listener should be able to stop the composition at any time, examine all 
the INSTRUMENT VOICES, take notes, and resume playing the piece. All 
those qualities were eventually built into the ST MUSIC BOX'S PLAYER. 

The COMDEX computer show deadline loomed on the horizon and we 
needed a minimum demo for the show. With that in mind we coded the 
music driver (most of what you will see in the file 'mdrive . c') first and 
then we hand assembled (grunt work) in the note data to John P. Sousa's 
"Stars and Stripes Forever". Keying in all the voices using our assembler 
was quite tedious, but it was worth the effort because it gave us note data 
which we eventually used to tune the music driver. The demo was readied 
in about ten days and we shipped it off to Xlent Software feeling that we 
had produced something "showable". 


96 



Abacus Software 


Atari ST MIDI Book 


Eventually we worked into the player the ability to control the music's speed 
(tempo) per measure and also we coded in the ability to change the 
instrument voice per measure. We thought that these were two very nifty 
features which would add a great deal to the musicality of the player. When 
we tried out those features on our Casio CZ series synthesizers we were 
delighted with the results. We could take a single line of music and have a 
flute play measure 1, a trumpet measure 2 and a whistler for measure three, 
etc. 

You can imagine our SHOCKING surprise when Len demoed the program 
at a New York user's group and discovered that a Kawai MIDI synthesizer 
delayed the play at the ONSET of EVERY measure as the PROGRAM 
CHANGE message was sent from the ST to the Kawai! In New York 
slang, "What a bummer!" Our nifty little idea of changing the instrument 
voice per measure using the PROGRAM CHANGE message turned an 
elegant feature into a headache. So much for the MIDI STANDARD and 
manufacturer implementations. We began a last minute code fix. 

Once we had finished the COMDEX demo we began the planning of the 
editor. Basically we decided that there would be two approaches we would 
consider: 1) moving the cursor over the music staffs and a click would place 
the note on the screen or 2) having the cursor move about a piano-like 
keyboard and clicking on a note would pop it up on a staff. We bandied 
about what to do for a while. There were pluses and minuses for both 
methods. 

On the surface, moving the cursor over the staff seemed the more elegant 
method, and some successful music programs on other computers used that 
method successfully. Len strongly argued against the more elegant looking 
method for a variety of reasons. He felt that having the opportunity to place 
the notes anywhere (horizontally or vertically) on the staffs was too much 
freedom for him. He felt that a more tightly structured method of note entry 
would facilitate with less "typos". Dennis brought up the notion of making 
the editor, in a few clever ways, syntax smart. 

We thought that reviewers might take us to task on our plain-Jane method of 
note entry, but we decided to follow our instincts and not worry about how 
reviewers might judge the editor's architecture. After all, our series of 
Printware Programs for Xlent Software on both the XE and ST Atari 
computers had been reviewed in approximately two dozen sources. These 
reviews ranged from being printed in large widely circulated magazines to 
small user group newsletters. It is abundantly clear that when programmers 
or builders of any engineering art form display their work in a public forum, 


97 



Abacus Software 


Atari ST MIDI Book 


most often the reviewers reaction will be mixed. What pleases some drives 
others nuts! Different strokes. We believe that the purest way to develop a 
product is to temper our creative vision with the opinions of those we 
respect. 

Eventually we chose the piano-like keyboard method of note entry. Here 
were some of the reasons that come to mind: 1) some people play the piano 
by ear and don't read music that well; 2) the cursor would have MUCH 
wider range for note entry - in theory, meaning fewer mechanical errors; 
and 3) there would be LESS travel between the keyboard for note entry and 
other musical qualities, such as duration icons. 

We have been programming as a team for over four years and know our 
strengths and weaknesses well. A great deal of our programming and Atari 
ST knowledge overlaps, so we delegate sections of code according qualities 
of challenge and fun. Each of us winds up with 'new and challenging 
code', that which we deem as 'fun code', and the loathesome 'grunt code'. 
In balance, our efforts are synergistic efforts. 

A rough editor was programmed quickly and then the ardous process of 
entering thousands of notes began. We refined both the player and editor 
during dozens of test hours. After a few weeks we realized that we had 
used the editor to create eight songs. When Len keyed in all the notes to a 
favorite Bach four voice fugue he realized that his and Dennis' vision for the 
editor worked very well. It was a breeze to enter the contrapuntal music 
which was enveloped in complex rhythmic patterns. It was a breeze to edit 
the note data and instrument voices. It was at that moment we had a truly 
solid product for the MIDI minded Atari ST owner. 

At that time we were about 7 days before the COMDEX computer show and 
decided we could upgrade the previous demo we had sent to Xlent Software 
and write the AUTO-PLAYER for the COMDEX show. We reasoned that 
having a program which would play song after song, as a long play record 
might, would make for a better demonstration than the process of selecting 
one song after another and loading it into the Atari ST's RAM. The sales 
person at the COMDEX booth could just turn on the AUTO-PLAYER and 
concentrate on the process of writing orders and greeting industry pundits. 

So was bom the ST MUSIC BOX AUTO-PLAYER. We programmed at 
warp speed getting the program to work. We weren't concerned about 
making the code as compact as possible: a fully operational demo for 
COMDEX was our goal. 


98 



Abacus Software 


Atari ST MIDI Book 


When the editors at Abacus Software asked us to write a book about the 
Atari ST and MIDI, we decided to use ALL the code in the AUTO-PLAYER 
and NOT cull out die fat. Here, again, we decided to not worry about how 
'C' wizard reviewers would evaluate the code. Including extra routines 
would provide extra tutorial for this book's readers. 

One specific example would be the function 'ldsnedk ()' in the source 
file ’set s . s'. The function 'ldsendk ()' could have been pulled from 
the code as it does not have anything to do with the AUTO-PLAYER, but it 
does show the reader one way to read the ST's mouse to determine which 
non-resource construction set ICON has been selected. The file 
'btdata. c' contains specific code presenting two ways to get ICONS up 
on the screen. As you may have deduced, the ICONS presented are those 
which appear on the editor screen of Xlent Software's ST MUSIC BOX 
and the routine ' ldsendk () ' determines which non-resource 
construction set an ICON has been selected. There are other examples of 
code which we've left from the ST MUSIC BOX intact because we believe 
it will prove useful to many. 

What follows is the 'C' source code for the ST MUSIC BOX 
AUTO-PLAYER. At the time the AUTO-PLAYER was written we were 
using the Alcyon compiler supplied in Atari's development package. 
Currently, we are using Megamax C to create our programs and recommend 
the Megamax package if your looking for a compiler. The price tag is pretty 
stiff at $200 retail in the U.S., but combined with some of Abacus' other 
ST books you'll find yourself, in our opinion, with a faster and more 
comprehensive C development system than that provided in the Atari 
package. 

On a different front: with the source code in this volume we tried to present 
a large amount of 'C' source code along with the MIDI information 
presented earlier. The actual source for the player runs along the lines to 
approximately 6000 lines of 'C' source, a massive amount to type in. The 
optional disk which may be purchased along with this book is a very good 
value if you are thinking of typing in the program. On the disk you'll find: 
1) the source typed in!; 2) compiled object files; and 3) MUSIC FILES for a 
Joplin rag, a Bach fugue, a ditty by F. Couperin ... and more! 


99 



Abacus Software 


Atari ST MIDI Book 


So if you plan to take the information presented in this book and start your 
own MIDI project you probably will not need the disk. If you want to hear 
the player, the modest price for the disk is an easy way to avoid some 
intense typing to wind up with no music files!!! 

On to the CODE! 


100 



Abacus Software 


Atari ST MIDI Book 


4.2 eio . c source code 


This program was created to demonstrate the capabilities of ST MUSIC 
BOX and to serve as a mechanism to automatically play pieces created with 
ST MUSIC BOX. For the most part it is culled from code that already 
existed in the main program. When we were creating ST MUSIC BOX we 
used three different C compilers and two assemblers, but most of it was 
produced with the Alcyon compiler that came with the developer's package. 
In order to make the code at least reasonably clear we have re-edited the 
whole hodgepodge and recompiled it with Alcyon. It works, but it certainly 
isn’t pretty. To tell the truth, our code is rarely pretty or even well tuned 
up. Our attitude in writing programs is that we get the model up and 
running and return to code only if the 'results' don't satisfy us. We've 
gotten used to ugly code and we've also gotten used to finishing things on 
time. Respect your language, but do not pay it homage. How's that for 
pompous ? 


/* 

** eio.c 
*/ 


/* 

** include definition files 
*/ 

#include <a:portab.h> 

#include <a:machine.h> 

#include <a:obdefs.h> 

tinclude <a:define.h> 

tinclude <a:gemdefs.h> 

tinclude <a:osbind.h> 

/* 

** declare global variables 
*/ 

int wbox, hbox, durl, dur2, dur3, port_state; 
int dur4,dur5,dur6,dur7,dur8; 

int contrl[12], intin[256], ptsin[256], ptsout[256]; 
int intin[256], intout[256],pxy[10] ; 

int newbyte[8], oldbyte[8], typedone, hboxl, wboxl, hcharl, wcharl; 
int 1 intin [20], l_out[128], l_ptsin[20]; 


101 



Abacus Software 


Atari ST MIDI Book 


int ev_kreturn, iter, gr_mkmx, grjnkmy, groption, stylem, endm, mode, set_mode; 

int set_font, handle, dummy, gr_mkmstate, gr_mkkstate, prtmem, set_ef feet; 

int holdx,holdy,whesc,whescl,color_index,colorm, holdclr; 

int gr_mkresvd,intstyle,topbot,height,width,widd,mull,radius; 

int begang,endang,yradius,x_boundary,y_boundary, k, kl,k2,k3,k4; 

int i,n,u,ab,kk,row,count,column,sp,mod,byte, j, quot, rem, demo; 

int notel, note2, note3,note4,note5,note6,note7,note8; 

int scrold, sernew, mult, ymult, findex, fcolor, linev, lineh, linesw; 

int bytel, byte2, ig, sgflag,prtsw,path; 

int timex, timey, first, octup, octswO, octswl, octsw2, measent, cnt32; 

int octsw3,octsw4,octsw5,octsw6,octsw7; 

int chancnt, progent, gfreql, gfreq2, gfreq3; 

int gfreq4,gfreq5,gfreq6,gfreq7,gfreq8; 

int *ptrl, *ptr2, *ptr3, *ptr4, *ptr5, *ptr6, gpsw, gvibsw, gptime; 

int dblol, *ptr7,*ptr8; 

int gprog, progtabf 512]; 

int file_handle; 

int kreturn; 

int exflag; 

int holdrez; 

int st_m =1; 

int chanl_buffer[264]; 
int chan2_buffer[264 ]; 
int chan3_buffer[2 64]; 
int chan4_buffer[2 64 ]; 

int topl_measure; 
int top2_measure; 
int top3_measure; 
int top4_measure; 
int top5_measure; 
int top6_measure; 
int top7_measure; 
int top8_measure; 

int octave =4; 

int measure =0; 

int key = 1; 

int time = 32; 

int time_counter =3; 

int key_counter = 1; 

int key_sw =1; 

int cml_pick = 1; 
int cm2_pick =2; 
int cm3_pick = 3; 


102 



Abacus Software 


Atari ST MIDI Book 


int cm4_pick =4; 

int chl_meas = 0; 
int ch2_meas = 0; 
int ch3_meas = 0; 
int ch4_meas = 0; 

int actl_measure = 1; /* preset 1*/ 
int act2_measure =2; /* preset 2*/ 
int act3_measure = 3; /* preset 3*/ 
int act4_measure =4/ /* preset 4*/ 

int thisl_measure; 
int this2_measure; 
int this3_measure; 
int this4_measure; 

int portl; 
int port2; 
int port3; 
int port4; 

int vibl = 0; 
int vib2 = 0; 
int vib3 = 0; 
int vib4 = 0; 

int octl =2; 
int oct2 =2/ 
int oct3 =2; 
int oct4 = 2; 
int oct5 =2; 
int oct6 =2; 
int oct7 =2; 
int oct8 =2; 

int vcl =1; 
int vc2 = 1; 
int vc3 =1/ 
int vc4 = 1; 
int vc5 = 1; 
int vc6 = 1/ 
int vc7 = 1; 
int vc8 = 1; 

int key_pick = 25; 
int xkey; 


103 



Abacus Software 


Atari ST MIDI Book 


int time_check; 
int key_check; 
int topxbuff[12 4] ; 
int xkey_input; 
int voice; 
int io_measure; 

int dbuffer[3250]; /* 250 * 13 */ 
int f; 

int f_check; 

int tm; 

int dcur_drv; 

int attr; 

int r_voice =1; 

int t,p,yy,y; 


long screenl,screen2,orgscrn,logicbase; 

long ltemp,buff_size,bufferx,l_ptrl; 

char xstr[2] = { *\0 , , , \0* }; 

char iobuffl[6336]; 

char iobuff2[6336]; 

char yspec[5]; 

char dta_name[64] = ,,M ; 

char xfile_name[64] = 

char c; 

char *ptra; 

char dig_buff[128] ; 

/*-Alcyon does not limit the number of bytes that can 

be designated as variables or allotted in arrays. With at least 
one of the C compilers available for the ST you are limited to 
32,000 bytes for these purposes. If you were using that compiler 
the bytes can be reserved with a malloc call (memory allocation) 
which is nicely explained in their documentation.-*/ 


char bufferl[32767]; /* main display screen */ 

char nbuffl[6336]; 
char nbuff2[6336]; 
char nbuff3[6336]; 
char nbuff4[6336]; 
char nbuff5[6336]; 
char nbuff6[6336]; 
char nbuff7[6336]; 
char nbuff8[6336]; 


104 





Abacus Software 


Atari ST MIDI Book 


char nbuff 9[6336]; 

char nbuff 10[6336]; 

char nbuff 11[6336]/ 

char nbuff 12[6336]; 

char nbuff 13[6336]; 

char nbuff 14[6336]/ 

char nbuff 15[6336]; 

char nbuff 16[6336]; 

char tmpo_buffer[264]; 


main () 

{ 


/* 


Standard initializations 


*/ 


app]_ init () r /* only one on board no ID really needed / 


/*—appl_init() will return a value to you to be used as an 
identification number if you're planning on having more 
than one program resident. 

In that case, you would write something like: 

appl_id = appl_init(); - 


for (i=0; i<10; ++i) 

{ 

intin[i] = 1/ 

} 

intin[10]=2; 

handle = graf_handle(Swidth,Sheight,&wbox,&hbox); 

/*- T he graf_handle function writes the letter width,letter height, 

character box width and character box height into the addresses 
you pass it. It returns a handle that is used each time 
you access the VDI.- x / 

v_opnvwk(intin, Shandle, intout)/ 
v_clrwk(handle) ; 

/*-Enable clipping function and establish initial parameters */ 


pxy[0]=0; 
pxy[1]=0/ 


105 









Abacus Software 


Atari ST MIDI Book 


pxy[2]=intout [0]; 
pxy[3]=intout [1]; 
x_boundary = pxy[2]/2; 
y_boundary = pxy[3]/2; 
vs_clip(handle,1,pxy)/ 

/ ^ ave separate programs for the medium and high resolution 

monitors(none for the low resolution), so we check the Gem 
function Getrez() before proceeding. This is the color version. 

The returned value are: 

Low resolution = 0; 

Medium resolution = 1; 

High resolution = 2; 

If the correct program / monitor combination is not established 
the user is returned to the desktop. 

siting if (Getrez () != 1) here does the trick nicely 

but we made other reference to screen resolution so we stuck it 
in a variable to avoid another call. -*/ 

holdrez = Getrez(); 
if (holdrez != 1) 

{ 

v_gtext(handle,width*0,height*3, 

"Xlent 1 s MUSIC BOX Player is for Med Res only!")/ 
v_gtext(handle,width*0,height*6, 

"PRESS ANY KEY for DESK TOP"); 
ev_kreturn = evnt_keybd()/ 

goto todesk; /* Exit to desktop */ 

} 

/* This next bit of code establishes the screen address; 

not all compilers will let you treat the long int 
screenl in this fashion but Alcyon does. There are other 
ways of setting the screen address but this was left over 
from another program that had buffers moving in, out, up, 
down, left and right, and we just stuck with it. For your 
information, a simple: 

orgscrn = (long) PhysbaseO; 
or 

orgscrn = (char *)Physbase(); (with some compilers) 
by itself, should get you going nicely. -*/ 


106 







Abacus Software 


Atari ST MIDI Book 


screenl = (OxfffOOSbufferl); 
screenl += (0x100); 
vsf_perimeter(handle,1) ; 


v_hide_c (handle); 
v_clrwk(handle); 
timex = 180; 
timey = 50; 


/*top screen addr*/ 
/*adjust ptr*/ 

/*edge of shape visible*/ 

/* hide mouse pointer */ 

/* clear the screen */ 

/* default tempo values */ 

/* - */ 


denw2(); /* a small window for title */ 

v_gtext(handle,width*22,height*8, 

" XLent Software presents")/ 
v_gtext(handle,width*22,height*10, 

" ST MUSIC BOX AUTOPLAYER (c) 1986"); 
v_gtext(handle,width*22,height*14, 

" by Dennis Young & Len Dorfman"); 
v_gtext(handle,width*22,height*15, 

" Press any Key to continue"); 
v_gtext(handle,width*22,height*ll, 

» V. 1.0"); 

v_gtext(handle,width*22,height*12, 

"From the Abacus book ATARI ST") ; 
v_gtext(handle,widt h*2 2,height *13, 

"Introduction to MIDI Programming") ; 


ev_kreturn = evnt_keybd(); 
v_clrwk(handle); 

while ( exflag == 0 ) 
iowork(); 

/★-jf resolution wrong or exflag != 0, program exits here. */ 


todesk: 


vst_height(handle,13,fiwcharl,Shcharl,&hbox,&wbox); 
set_effect = vst_effects(handle, 0) ; 
vst_rotation(handle, 0) ; 
vswr_mode(handle, 0) ; 

v_clrwk(handle) ; /*clear the screen*/ 

v clsvwk(handle); 


} 

/* 


*/ 


•end main 


107 







Abacus Software 


Atari ST MIDI Book 


/* This is set up to repeat the whole process 20 times 


iowork () 

{ 

int uuu,jjj, fff,yyy,ccc; 
getl_path<) ; 

for (ccc = 0;ccc < 20; ++ccc) 

{ 

for (jjj = 0, uuu = 0, yyy = 0; jjj < tm; ++jjj, ++uuu) 

{ 

dcur_drv = Dgetdrv(); 
xfile_name[0] = dcur_drv + 'A'; 
xfile_name[1] = 

for (fff = 2; fff < 15; ++fff, ++yyy) 
xfile_name[fff] = dbuffer[yyy]; 


do_c_load (); 
playit () ; 

} 

} 

} 

/* 

★ ★ 

*/ 

ex_mode() 

{ yspec[0] 

yspec[l] 
yspec[2] 
yspec[3] 
yspec[4] 

} 


= »★ i 

= i i 

= * M 1 
= »U' 
= 'S' 


clrdta () 

{ 


} 


for (f = 30; f < 43; 

dta_name[f] = 


++f) 

32; 


■*/ 


108 






Abacus Software 


Atari ST MIDI Book 


clr_dbuffer() 

{ 

for (f =0; f < 3250; ++f) 

dbuffer[f] = 32; 


} 


/* 
★ ★ 

*/ 


char 

*qqstr (pd, ps) 
char *pd, *ps; 

{ 

while (*pd) 
pd++; 

while (*pd++ = *ps++); 
return(pd); 

} 


/*-This routine bypasses the fsel_input routine that fetches the 

standard Gem 10 Window. It reads into a buffer the names 
of all the files that have the extender .MUS and it can handle 
250 files. There is no major advantage to doing it this way over 
looping through the directory for each title but with so much 
memory it just felt right. We've detailed most of the 10 code 
since not everyone is very familiar with ST disk work and 
it's easy to get lost in.-*/ 


getl_path () 

{ 

int i, y; 


attr = 0x17; 
tm = 0; 

clr_dbuffer (); 
ex_mode (); 

vst_effects(handle, 0); 

for (i=0; i < 64; i+ + ) 
xfile_name[i] = 0; 


109 





Abacus Software 


Atari ST MIDI Book 


l_ptrl is a long pointer which is used to pass the address of a 
buffer to which a subsequent call - FsfirstO - is going to 
write data. This buffer should be allotted 64 bytes to hold the 
data that's going to be coming back. It's referred to as the 
disk transfer address-*/ 

l_ptrl = dta_name; 

Fsetdta(l_ptrl); 


/★ Dgetdrv returns the number of the current disk drive (0 = A:, 

1 = B: r 2 = C:, etc.). In order to make the drive designator 
consistent with what's required for other 10 work - ASCII is passed 
back and forth - we add the ASCII value for 'A' to the number 
returned. -- 

dcur_drv = Dgetdrv(); 
xfile_name[0] = dcur_drv + 'A'/ 
xfile_name[1] = 

/*-Dgetpath returns the current path or folder into our filename 

buffer. After that we concatenate the extender.-*/ 

Dgetpath( &xfile_name[2], dcur_drv +1); 
qqstr(xfile_name,yspec); 


/*-Attr is a set of attributes that are to be matched. 


$01 read only 

$02 hidden 

$04 system (hidden) 

$08 volume label 

$10 subdirectory 

$20 written to and closed 


Fsfirst dumps data into the our xfile_name buffer. The function 
actually calls for the first parameter passed to be a char 
pointer to the buffer. We are only looking for the filename and 
its extender but there is other information provided. 

file attributes byte 21 

file time stamp byte 22-23 

file date stamp byte 24-25 

file size (as a long) byte 26-29 
name/extender of file byte 30-43 


no 










Abacus Software 


Atari ST MIDI Book 


A 0 is returned if the file is found. The loop following FsfirstO 
starts loading the filenames into a buffer which will eventually 
serve to hold all of the eligible files (those with MUS 
extender).-*/ 


ptrl = xfile_name; 

f_check = (Fsfirst( ptrl, attr )); 

for (i = 0,f = 30; f < 43; ++i, ++f) 
dbuffer[i] = dta_name[f]; 
clrdta () ; 


/*-FsnextO continues the process started by FsfirstO; it 1 s not 

necessary to pass any parameters - you must only extract whatever 
information you want. The loop will get as many as 250 names 
and plop them all into dbuffer[3250] :: 250 * 13 bytes each. —*/ 


i = 13; /* one file already in place from FsfirstO */ 

do 

{ 

f_check = FsnextO; 

if ((f_check == 0) && (tm < 250)) 

{ " 

++tm; 

for (f = 30; f < 43; ++f,++i) 
dbuffer[i] = dta_name[f]; 
clrdta () ; 

) 

} 

while (f_check==0) ; 

} 


clr_iobuff() 

{ 

for (f =0; f < 6336; ++f) 

{ 

iobuffl[f] = 0; 
iobuff2[f] = 0; 

} 

} 


ill 




Abacus Software 


Atari ST MIDI Book 


/* 

We set up these buffers apart from each other to allow 
easier, more explicit access to them. At various times in the 
program*s developement, we would have different buffers and 
counters on the screen to make for easy debugging. Pointing 
into a single large array is cumbersome in cases where so 
many unlike variables are being tracked. 

The Midi likes to pass 16 bit values and that's the reason we 
used them instead of chars. The exception is the tmpo_buffer 
which was cut in last - we hadn't left enough room in the header 
to accomodate it as 16 bit numbers so we put it in as chars and 
convert them before the value is passed. 

*/ 


get_counters () 

{ 

bufferx = &chanl_buffer[0]; 
buff_size = 528; 

Fread(file_handle,buff_size,bufferx) ; 

bufferx = &chan2_buffer[0]; 
buff_size = 528; 

Fread(file_handle,buff_size,bufferx) ; 

bufferx = &chan3_buffer[0]; 
buff_size = 528; 

Fread(file_handle,buff_size,bufferx) ; 

bufferx = &chan4_buffer[0]; 
buff_size = 528; 

Fread(file_handle,buff_size,bufferx) ; 

bufferx = &topxbuff[0]; 
buff_size = 248; 

Fread(file_handle,buff_size,bufferx) ; 

bufferx = &tmpo_buffer[0] ; 
buff_size = 264; 

Fread(file_handle,buff_size,bufferx) ; 

topl_measure = topxbuff[0]; 
top2_measure = topxbuff[l]; 
top3_measure = topxbuff[2]; 
top4_measure = topxbuff[3]; 
top5_measure = topxbuff[4]; 


112 



Abacus Software 


Atari ST MIDI Book 


top6_measure 

top7_measure 

top8_measure 


topxbuff[5]; 
topxbuff[6] ; 
topxbuff[7]; 


key = topxbuff[8]; 
time = topxbuff[9]; 


cml_pick 
cm2_pick 
cm3_pick 
cm4_pick 
chl_meas 
ch2_meas 
ch3_meas 
ch4 meas 


topxbuff[10] / 
topxbuff[11]/ 
topxbuff[12]; 
topxbuff[13]; 
topxbuff[14]; 
topxbuff[15]; 
topxbuff[16]; 
topxbuff[17]; 


actl_measure 
act2_measure 
act3_measure 
act4 measure 


= topxbuff[18] ; 
= topxbuff[19] ; 
= topxbuff[20] ; 
= topxbuff[21]; 


thisl__measure 
this2_measure 
this3_measure 
this4 measure 


= topxbuff[22]; 
= topxbuff[23]; 
= topxbuff[24]; 
= topxbuff[25]; 


timex = topxbuff[26]; 
timey = topxbuff[27]; 


portl = topxbuff[28]; 
port2 = topxbuff[29]; 
port3 = topxbuff[30]; 
port4 = topxbuff[31]; 

vibl = topxbuff[32] ; 
vib2 = topxbuff[33]; 
vib3 = topxbuff[34]; 
vib4 = topxbuff[35] ; 

octl = topxbuff[36]; 
oct2 = topxbuff[37] / 
oct3 = topxbuff[38]; 
oct4 = topxbuff[39]; 
oct5 = topxbuff[40] ; 
oct6 = topxbuff[41 ] / 
oct7 = topxbuff[42]; 
oct8 = topxbuff[43] ; 


113 



Abacus Software 


Atari ST MIDI Book 


vcl = topxbuff[44] ; 
vc2 = topxbuff[45]; 
vc3 = topxbuff[46]; 
vc4 = topxbuff[47]; 
vc5 = topxbuff[48]; 
vc6 = topxbuff[49]; 
vc7 = topxbuff[50]; 
vc8 = topxbuff[51]; 

time_counter = topxbuff[52]; 
key_counter = topxbuff[53]; 
xkey = topxbuff[54]; 


} 

/* 

★ ★ 

*/ 

do_c_load() 

{ 

int check; 

int ii; 


/*-Fopen wants the file name and a mode value which will be 0 

for read, 1 for write or 2 for read / write; the operation 
returns a number that serves has a file designator. It will 
return a negative number in the event of an error.-*/ 

file_handle = Fopen (ADDR(xfile_name), 2); 
if (file_handle >= 0) 

{ 

get_counters(); 

for (r_voice = 1; r_voice < 9; ++r_voice) 

{ 

clr_iobuff(); 
nmove(); 
mv_io_n () ; 

} 


114 





Abacus Software 


Atari ST MIDI Book 


/* 


} 


•Fclose needs only the file designator to wrap it up -*/ 

Fclose(file_handle) ; 

} 


/* 

** 

*/ 


nmove() 

{ 

int cc,mm; 

/*-Fread needs three things: 

1. File designator or handle 

2. Number of bytes to read stored in a long 

3. Char pointer to receiving buffer(though Alcyon also 
happily accepts a long with the buffer address as it is 
here) 

The number of bytes actually read is returned so if you need or 
want to know the number, set up the call like this: 

(int or long) number = Fread (handle, count, buffer) ;-*/ 


for(mm =0/ mm < 264 ; ++mm) 

{ 

for(cc = 0; cc< 24 ; ++cc) 

{ 

bufferx = &xstr[0]; 
buff_size = 1; 

Fread(file_handle,buff_size,bufferx) ; 
if (xstr[0] != 249) 

iobuffl[(mm * 24) + cc] = xstr[0]; 

else 

cc = 24; 

} 

} 

for(mm = 0; mm < 264 ; ++mm) 

{ 

for(cc = 0; cc< 24 ; ++cc) 


115 







Abacus Software 


Atari ST MIDI Book 


{ 

bufferx = &xstr[0]; 
buff_size =1; 

Fread(file_handle,buff_size,bufferx) ; 
if (xstr[0] != 249) 

iobuff2[(mm * 24) + cc] = xstr[0]; 

else 

cc = 24; 

} 


} 

/* 

★ ★ 

*/ 

mv_io_n() 
{ ~ 


switch(r_voice) 

{ 


case 0x01: 

for ( yy = 0; yy < 6336; ++yy) 


{ 

nbuffl[yy] = 
nbuff2[yy] = 
} 

break; 
case 0x02: 
for ( yy = 0; yy 
{ 

nbuff3[yy] = 
nbuff4[yy] = 
} 

break; 
case 0x03: 
for ( yy = 0; yy 
{ 

nbuff5[yy] = 
nbuff6[yy] = 
} 

break; 
case 0x04: 
for ( yy = 0; yy 
{ 

nbuff7[yy] = 


iobuff1[yy]; 
iobuff2[yy]; 


< 6336; ++yy) 

iobuff1[yy]; 
iobuff2[yy]; 


< 6336; ++yy) 

iobuff1[yy]; 
iobuff2[yy]; 

< 6336; ++yy) 
iobuff1[yy]; 


116 



Abacus Software 


Atari ST MIDI Book 


nbuff8[yy] = iobuff2[yy]; 

} 

break; 
case 0x05: 

for ( yy = 0; yy < 6336; ++yy) 

{ 

nbuff9[yy] = iobuffl[yy]; 
nbufflO[yy] = iobuff2[yy]; 
} 

break; 
case 0x06: 

for ( yy = 0; yy < 6336; ++yy) 

{ 

nbuffll[yy] = iobuffl[yy]; 
nbuffl2[yy] = iobuff2[yy]; 
} 

break; 
case 0x07: 

for ( yy = 0; yy < 6336; ++yy) 

{ 

nbuffl3[yy] = iobuffl[yy]; 
nbuffl4[yy] = iobuff2[yy]; 
} 

break; 
case 0x08: 

for ( yy = 0; yy < 6336; ++yy) 
{ 

nbuffl5[yy] = iobuffl[yy]; 
nbuff16[yy] = iobuff2[yy]; 
} 

break; 

default: 
break; 

} 


denw2() 

{ 

int pxy8 [10]; 
setldparam(); 

pxy8[0] = 160 - 8; 
pxy8[1] = (128 - 48)/2; 
pxy8[2] = 480; 
pxy8[3] = (128 - 48)/2; 


117 



Abacus Software 


Atari ST MIDI Book 


pxy8[4] = 480; 

pxy8[5] = 272/2; 

pxy8[6] = 160 - 8; 

pxy8[7] = 272/2; 

pxy8[8] = 160 - 8; 

pxy8[9] = (128 - 48)/2; 

pxy[0] = 160 - 8; 

pxy[1] = (128 - 48)/2; 

pxy[2] = 480; 

pxy[3] = 272/2; 

vr_recfl(handle,pxy); 

v_pline(handle,5,pxy8); 

vsf_interior(handle,0); 

pxy8[0] = 168 - 8; 

pxy8[1] = (144 - 48)/2; 

pxy8[2] = 472; 

pxy8[3] = (144 - 48)/2; 

pxy8[4] = 472; 

pxy8[5] = 256/2; 

pxy8[6] = 168 - 8; 

pxy8[7] = 256/2; 

pxy8[8] = 168 - 8; 

pxy8[9] = (144 - 48)/2; 

pxy[0] = 168 - 8; 

pxy[1] = (144 - 48)/2; 

pxy[2] = 472; 

pxy[3] = 256/2; 

vr_recfl(handle,pxy); 

vsl_width(handle,1); 

v_pline(handle,5,pxy8); 


setldparam() 

{ 

vsf_color(handle,1); 
vswr_mode(handle, 1) ; 
vsf_interior(handle, 2) ; 
vsl_width(handle, 1) ; 
vsl_color(handle, 1); 

vsf_style(handle, 1) ; 

} 

/* 

** end eio.c 
*/ 


118 



Abacus Software 


Atari ST MIDI Book 


4.3 mdrive . c source code 


This file is the main music driver file. It will play simultaneously from the 
console speaker and through the MIDI port. 


/* mdrive.c 


*/ 


/* 

** include definition files 
*/ 


♦include 

♦include 

♦include 

♦include 

♦include 

♦include 


<a:portab.h> 
<a:machine. h> 
<a:obdefs.h> 
<a:define.h> 
<a:gemdefs,h> 
<a:osbind.h> 


/* 

** external definitions 
*/ 


extern 

extern 

extern 

extern 

extern 

wcharl; 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 


int wbox, hbox, durl, dur2, dur3, port_state; 
int dur4,dur5,dur6,dur7,dur8; 

int contrl[12], intin[256], ptsin[256], ptsout[256]; 
int intin [256], intout [256],pxy[10]; 

int newbyte[8], oldbyte[8], typedone, hboxl, wboxl, hcharl, 
int l_intin[20], l_out[128], l_ptsin[20]; 

int ev_kreturn,i,iter,gr_mkmx,gr_mkmy,groption,stylem,endm; 
int mode,set_mode; 

int set_font,handle,dummy,gr_mkmstate, gr_mkkstate,prtmem; 
int holdrez,set_effeet; 

int holdx,holdy,whesc,whescl,color_index,colorm,holdclr; 
int gr_mkresvd,intstyle,topbot,height,width,exflag; 
int widd,mull,radius; 

int begang,endang,yradius,x_boundary, y_boundary, k,kl,k2,k3,k4; 
int n,u,ab,kk,row,count,column,sp,mod, byte,j,quot,rem,demo; 
int notel, note2, note3, note4, note5, note6, note7, note8; 
int scrold, sernew, mult, ymult, findex, fcolor, linev; 
int lineh, linesw; 

int bytel, byte2, ig, sgflag,prtsw,path; 
int timex, timey, first, octup; 


119 



Abacus Software 


Atari ST MIDI Book 


extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

int 


int octswO, octswl, octsw2, octsw3, octsw4, octsw5, octsw6; 
int octsw7, meascnt, cnt32; 
int chancnt, progcnt; 

int gfreql, gfreq2, gfreq3, gfreq4,gfreq5, gfreq6,gfreq7,gfreq8; 
int gpsw, gptime, dblol, gvibsw, gprog; 

long *ptrl, *ptr2, *ptr3, *ptr4, *ptr5, *ptr6, *ptr7, *ptr8; 

char c; 

long logicbase,screenl,screen2, orgscrn,ltemp; 

char bufferl[32767]; /* main display screen */ 

int fflagl,fflag2,fflag3,fflag4,fflag5, fflag6, fflag7,fflag8; 

int octl, oct2, oct3, oct4, oct5, oct6, oct7, oct8; 

int prog0c[264], proglc[264], prog2c[264], prog3c[264]; 

int vcl, vc2, vc3, vc4, vc5, vc6, vc7, vc8, time; 

ldtmpo[ 264 ]; 


/*-program start 


*/ 


int gpflag; 

int gprogl, gprog2, gprog3; 


/* 

** for future use 
*/ 


beepl() 

{ 

} 


/★-demo music buffers-*/ 


int dtabl[1024], 
dtab4[1024], 
dtab7[1024], 


dtab2[1024],dtab3[1024], 
dtab5[102 4],dtab6[1024] , 
dtab8[1024]; 


int ftabl[1024], 
ftab4[1024], 
ftab7[1024], 


ftab2[1024],ftab3[1024], 
ftab5[1024] f ftab6[1024], 
ftab8[1024]; 


int vtabl[1], 
vtab4[1], 
vtab7[1] , 


vtab2[1],vtab3[1], 
vtab5[1] f vtab6[1], 
vtab8[1]; 


int progtab; 


120 







Abacus Software 


Atari ST MIDI Book 


/* 

** these values are taken directly from the General 
** Instruments manual for the sound chip inside the 
** ST. You need to pass the chip a fine tune value 
** and a coarse tune value in order to produce a 
** legal note frequency. The ftune and ctune tables 
** will simplify playing music from the consol speaker. 
** The process is to index these arrays and then pass 
** the GI sound chip an index value ranging from 1 
** to 96. 

*/ 


/*-GI sound chip frequency values-*/ 


/* 50 */ 

int ftune[97] 
Oxf f, 

0x5d,0x9c, 
0x80,0x14, 
0x35,Oxf9, 
0x5d,0x36, 
0x53,0x40, 
Oxbe,0xb4, 
0x6b,0x65, 
0x3c,0x39, 
0x22,0x20, 
0x13,0x12, 

int ctune[97] 
Oxf f, 

OxOd,0x0c, 
0x07,0x07, 
0x04,0x03, 
0x02,0x02, 
0x01,0x01, 
0x00,0x00, 
0x00,0x00, 
0x00,0x00, 
0x00,0x00, 
0x00,0x00, 


= { 

0xe7,0x3c,0x9b,0x02, 
Oxae,0x4e,0xf4,0x9e, 
OxcO,0x8a,0x57,0x27, 
Oxlb,Oxfc,OxeO,0xc5, 
0x2e,Oxld,OxOd,Oxfe, 
Oxaa,OxaO,0x97,0x8f, 
0x5f,0x5a,0x55,0x50, 
0x35,0x32,0x30,0x2d, 
Oxle,Oxlc,Oxlb,0x19, 
0x11,0x10,OxOf,OxOe 

= { 

0x0b,0x0b,0x0a,0x0a, 
0x06,0x06,0x05,0x05, 
0x03,0x03,0x03,0x03, 
0x02,0x01,0x01,0x01, 
0x01,0x01,0x01,0x00, 
0x00,0x00,0x00,0x00, 
0x00,0x00,0x00,0x00, 
0x00,0x00,0x00,0x00, 
0x00,0x00,0x00,0x00, 
0x00,0x00,0x00,0x00 


0x73,Oxeb,0x6b,0xf2, 
0x4d,0x01,0xb9,0x75, 
Oxfa,Oxcf,0xa7,0x81, 
Oxac,0x94,0x7d,0x68, 
Oxf0,0xe2,0xd8,Oxca, 
0x87,0x7f,0x78, 0x71, 
0x4c,0x47,0x43,0x40, 
0x2a,0x2 8,0x2 6, 0x24 , 
0x18,Oxl6,0x15,0x14, 
} ; 


0x0 9,0x08,0x08,0x07, 
0x05,0x05,0x04,0x04, 
0x02,0x02,0x02,0x02, 
0x01,0x01,0x01,0x01, 
0x00,0x00,0x00,0x00, 
0x00,0x00,0x00,0x00, 
0x00,0x00,0x00,0x00, 
0x00,0x00, 0x00, 0x00, 
0x00,0x00, 0x00, 0x00, 
} ; 


/*-set the asdr envelope-*/ 

/*- ftl _> o - 32000-*/ 

/*-ctl -> 0 - 32000-*/ 

/*-ens -> 0,4,8,9,10,11,12,13,14,15 — */ 

setenv( ftl, ctl, ens) 


121 












Abacus Software 


Atari ST MIDI Book 


int ftl, ctl, ens; 
{ 


Giaccess 

( ftl. 

0x8b ); 

/* 

fine tune env speed */ 

Giaccess 

( ctl. 

0x8c ); 

/* 

coarse tune env speed */ 

Giaccess 

( ens. 

0x8d ); 

/* 

select env shape 


*/ 

} 

/* 

** This function writes to the MIDI 
** and will tell the keyboard synthesizer 
** to change the portamento value. See the 
** MIDI LANGUAGE section on control codes for more 
** infiormation. 

*/ 

/*-change portimento-*/ 

chport ( psw, ptime, pchan ) 
int psw, ptime, pchan; 

{ 

if ( pchan == 0 ) 
gptime = ptime; 
switch ( ptime ) 

{ 

case 0x00: 

Bconout ( 3, ( 128 + 32 + pchan + 16 ) ); 

Bconout ( 3, 65 ); /* 100 */ 

Bconout ( 3, 0 ); 
break; 
default: 

Bconout (3, ( 128 + 32 + pchan + 16 ) ); 

Bconout ( 3, 65 ); 

Bconout ( 3, 127 ); 

Bconout ( 3, ( 128 + 32 + pchan + 16 ) ); 

Bconout ( 3, 5 ); 

Bconout ( 3, ptime ); 

break; 

} 

} 


/*-change portamento-*/ 

chvib ( vtime, vchan ) 
int vtime, vchan; 

{ 

switch ( vtime ) 


122 







Abacus Software 


Atari ST MIDI Book 


} 


{ 

case 0x00: 
Bconout 
Bconout 
Bconout 
break; 
default: 

Bconout 

Bconout 

Bconout 

break; 

} 


( 3, ( 128 + 32 + vchan + 16 ) 

( 3 , 1 ); /* 100 */ 

( 3, 0 ); 


( 3, ( 128 + 32 + vchan + 16 ) 

(3, 1 ); 

( 3, 127 ); 


) ; 


) ; 


/* 

** This simple function allows you to 

** change the program, or instrument 

** voice for a specific CHANNEL. On entry 

** it receives the CHANNEL # and then 

** the PROGRAM #. The instrument corresponding 

** to the program number can be found in your 

** synthesizer's manual. 

*/ 

/*-set progeram change-*/ 

chprog ( chan3, prog ) 
int chan3, prog; 

{ 

Bconout ( 3, (128 + 64 + chan3 ) ); 

Bconout ( 3, prog ); 

} 

/* 

** This function turns a note off. 

** The reason why the freq— appears 
** is that the index for the frequency 
** in the player and editor begins with 
** the lowest 'C' having the value of 1. 

** The lowest 'C' on the MIDI synthesizer 
** will be 0, hence the freq—. 

*/ 

/*-midi note off-*/ 


noteoff ( chanl, veil, freql ) 
int chanl, veil, freql; 


123 







Abacus Software 


Atari ST MIDI Book 


{ 

if ( freql <= 36 ) 
freql = 1; 

else 

freql—; 

Bconout ( 3, 128 + chanl ); /* octave */ 

Bconout ( 3, freql ); /* casio default..temp */ 

Bconout ( 3, 0 ); /* freq playing */ 

} 


/* 

** This function turns a note on. The 
** if...else if...else code adjusts out 

** of bounds notes to play on the Casio 
** CZ 101. In this version of the 
** AUTO-PLAYER the default frequency index 
** value for a rest is 1. The call is 
** passed: first the channel in which to 
** turn he voice on, second, the velocity 
** (or note loudness), and third the index 
** representing the note to be played. 

** Note that the VELOCITY is NOT used in this 
** AUTO-PLAYER as we have chosen the default 
** value of 64. On future MIDI products we 
** will change the default value to reflect 
** a real volume. As the ST MUSIC BOX 1.1 does 
** allow the user to change VELOCITY we saw no 
** no reason to use the passed parameter. 

*/ 

/*-midi note on-*/ 

noteon ( chan2, vel2, freq2 ) 
int chan2, vel2, freq2; 

{ 

if ( freq2 == 1 ) 
freq2 = 1; 

else if ( freq2 <= 12 ) 
freq2 += 36/ 
else if ( freq2 <= 24 ) 
freq2 += 24; 
else if ( freq2 <= 36 ) 
freq2 += 12; 

else if ( freq2 >= 132 ) 
freq2 -= 36; 

else if ( freq2 >= 120 ) 


124 





Abacus Software 


Atari ST MIDI Book 


freq2 -= 24; 

else if ( freq2 >= 108 ) 
freq2 -= 12; 

else 

freq2 = freq2; 

if ( freq2 <= 36 ) 
freq2 =1; 

else 

freq2—; 

switch ( freq2 ) 

{ 

case 0x01: 



Bconout 

( 3, 128 + 

chan2 ); 

/* 

octave */ 




Bconout 

( 3, freq2 

); 

/* 

casio default 

..temp */ 



Bconout 

( 3, 0 ); 


/* 

freq playing 

*/ 



break; 




default: 




Bconout 

( 3, 128 + 

chan2 + 


Bconout 

( 3, freq2 

); 

/* 

casio default 

..temp */ 



Bconout 

( 3, 64 ) ; 


/* 

freq playing 

*/ 



break; 


} 

} 

/* 

** There are eight voices permissible 
** with the AUTO-PLAYER, although 
** upping the number of voices to 16 
** would be a snap. The variable oct 
** holds a value which tells the 
** AUTO-PLAYER if a note has been shut 
** off. The function call noteoff turns 
** the MIDI note off. 

*/ 

/*- 0 ff voice 1-*/ 


offvl() 

{ 


125 





Abacus Software 


Atari ST MIDI Book 


int foff, addit; 
if ( notel != 0 ) 

{ 

notel—; /* restore old value */ 

foff = ftabl[ notel ]; /* midi spec adjust */ 

switch ( octl ) 

{ 

case 0x01: 

gfreql = -12; 
break; 
case 0x02: 

gfreql = 0; 
break; 
default: 

gfreql = 12; 
break; 

} 

noteoff ( 0, 0, foff + gfreql ); 

/* turn note off */ 

notel++; /* restore new val */ 

} 

} 


/*-off voice 2-*/ 


offv2() 

{ 

int foff, addit; 
if { note2 != 0 ) 

{ 

note2—; /* restore old value */ 

foff = ftab2[ note2 ]; /* midi spec adjust */ 

switch ( oct2 ) 

{ 

case 0x01: 

gfreq2 = -12; 
break; 
case 0x02: 

gfreq2 = 0; 
break; 
default: 

gfreq2 = 12; 
break; 

} 

noteoff ( 0, 0, foff + gfreq2 ); /* turn note off */ 
note2++; /* restore new val */ 

} 


126 





Abacus Software 


Atari ST MIDI Book 


} 


/*- 0 ff voice 3-*/ 


offv3() 

{ 

int foff, addit; /* 200 */ 
if ( note3 != 0 ) 

{ 

note3—; /* restore old value */ 

foff = ftab3[ note3 ]; /* midi spec adjust */ 

switch ( oct3 ) 

{ 

case 0x01: 

gfreq3 = -12; 
break; 
case 0x02: 

gfreq3 = 0; 
break; 
default: 

gfreq3 = 12; 
break; 

} 

noteoff ( 1, 0, foff + gfreq3 ); 

/* turn note off */ 

note3++; /* restore new val */ 

} 

} 


/*- 0 ff voice 4-*/ 

offv4() 

{ 

int foff, addit; /* 200 */ 
if ( note4 != 0 ) 

{ 

note4—; /* restore old value */ 

foff = ftab4[ note4 ]; /* midi spec adjust */ 

switch ( oct4 ) 

{ 

case 0x01: 

gfreq4 = -12; 
break; 
case 0x02: 

gfreq4 = 0; 
break; 
default: 


127 







Abacus Software 


Atari ST MIDI Book 


gfreq4 = 12; 
break; 

} 

noteoff ( 1, 0, foff + gfreq4 ); 

/* turn note off */ 

note4++; /* restore new val */ 

} 

} 


/*- 0 ff voice 5-*/ 


offv5() 

{ 

int foff, addit; /* 200 */ 
if ( note5 != 0 ) 

{ 

note5—; /* restore old value */ 

foff = ftab5[ note5 ]; /* midi spec adjust */ 

switch ( oct5 ) 

{ 

case 0x01: 

gfreq5 = -12; 
break; 
case 0x02: 

gfreq5 = 0; 
break; 
default: 

gfreq5 = 12; 
break; 

} 

noteoff ( 2, 0, foff + gfreq5 ); /* turn note off */ 
note5++; /* restore new val */ 

} 

} 


/★- 0 ff voice 6-*/ 


offv6() 

{ 

int foff, addit; /* 200 */ 
if ( note6 != 0 ) 

{ 

note6—; /* restore old value */ 

foff = ftab6[ note6 ]; /* midi spec adjust */ 

switch ( oct6 ) 

{ 

case 0x01: 


128 







Abacus Software 


Atari ST MIDI Book 


gfreq6 = -12/ 
break; 
case 0x02: 

gfreq6 = 0; 
break; 
default: 

gfreq6 = 12; 
break; 

} 

noteoff ( 2, 0, foff + gfreq6 ); /* turn note off */ 
note6++; /* restore new val */ 


} 

} 


/*- 0 ff voice 7-*/ 


offv7 () 

{ 

int foff,- addit; /* 200 */ 
if ( note7 != 0 ) 

{ 

note7—; /* restore old value */ 

foff = ftab7[ note7 ]; /* midi spec adjust */ 

switch ( oct7 ) 

{ 

case 0x01: 

gfreq7 = -12; 
break; 
case 0x02: 

gfreq7 = 0; 
break; 
default: 

gfreq7 = 12; 
break; 

} 

noteoff ( 3, 0, foff + gfreq7 ); /* turn note off */ 
note7++; 

} /* restore new val */ 

} 


/*-off voice 8-*/ 


offv8() 

{ 

int foff, addit; /* 200 */ 
if ( note8 != 0 ) 

{ 


129 







Abacus Software 


Atari ST MIDI Book 


note8—; /* restore old value */ 

foff = ftab8[ note8 ]; /* midi spec adjust */ 

switch ( oct8 ) 

{ 

case 0x01: 

gfreq8 = -12; 
break; 
case 0x02: 

gfreq8 =0; 
break; 
default: 

gfreq8 = 12; 
break; 

} 

noteoff ( 3, 0, foff + gfreq8 ); /* turn note off */ 
note8++; /* restore new val */ 

} 

} 


/* 

** These routines turn the voices 
** on. The variable fon will hold a 
** number which will holds the note 
** value. If the note value is a 1 
** then the note is turned off and a 
** rest is simulated. 

*/ 

/*- on voice 1-*/ 

onvl() 

{ 

int fon, addit; 

fon = ftabl[ notel ]; /* midi spec adjust */ 

switch ( octl ) 

{ 

case 0x01: 

gfreql = -12; 
break; 
case 0x02: 

gfreql = 0; 
break; 
default: 

gfreql = 12; 
break; 

} 


130 





Abacus Software 


Atari ST MIDI Book 


switch ( fon ) 

{ 

case 0x01: 

noteoff ( 0, 0, fon + gfreql ); 
break; 
default: 

noteon ( 0, 64, fon + gfreql ); 
break; 

} 

} 

/*- 0 ff voice 2-*/ 

onv2 () 

{ 

int fon, addit; 

fon = ftab2[ note2 ]; /* midi spec adjust */ 

switch ( oct2 ) 

{ 

case 0x01: 

gfreq2 = -12; 
break; 
case 0x02: 

gfreq2 = 0; 
break; 
default: 

gfreq2 = 12; 
break; 

} 

switch ( fon ) 

{ 

case 0x01: 

noteoff ( 0, 0, fon + gfreq2 ); 
break; 
default: 

noteon ( 0, 64, fon + gfreq2 ); 
break; 

} 

} 

/*-on voice 3-*/ 

onv3() 

{ 

int fon, addit; 


131 







Abacus Software 


Atari ST MIDI Book 


fon = ftab3[ note3 ]; /* midi spec adjust */ 

switch ( oct3 ) 

{ 

case 0x01: 

gfreq3 = -12; 
break; 
case 0x02: 

gfreq3 = 0; 
break; 
default: 

gfreq3 = 12; 
break; 

} 

switch ( fon ) 

{ 

case 0x01: 

noteoff ( 1, 0, fon + gfreq3 ); 
break; 
default: 

noteon ( 1, 64, fon + gfreq3 ); 
break; 

} 

} 

/*- on voice 4-*/ 

onv4 () 

{ 

int fon, addit; 

fon = ftab4[ note4 ]; /* midi spec adjust */ 

switch ( oct4 ) 

{ 

case 0x01: 

gfreq4 = -12; 
break; 
case 0x02: 

gfreq4 =0; 
break; 
default: 

gfreq4 = 12; 
break; 

} 

switch ( fon ) 

{ 

case 0x01: 

noteoff ( 1, 0, fon + gfreq4 ); 
break; 


132 





Abacus Software 


Atari ST MIDI Book 


default: 

noteon ( 1, 64, fon + gfreq4 ); 
break; 

} 

} 

/*- on voice 5-*/ 

onv5 () 

{ 

int fon, addit; 

fon = ftab5[ note5 ]; /* midi spec adjust */ 

switch ( oct5 ) 

{ 

case 0x01: 

gfreq5 = -12; 
break; 
case 0x02: 

gfreq5 = 0; 
break; 
default: 

gfreq5 = 12; 
break; 

} 

switch ( fon ) 

{ 

case 0x01: 

noteoff ( 2, 0, fon + gfreq5 ); 
break; 
default: 

noteon ( 2, 64, fon + gfreq5 ); 
break; 

} 

} 

/*- on voice 6-*/ 

onv6() 

{ 

int fon, addit; 

fon = ftab6[ note6 ]; /* midi spec adjust */ 

switch ( oct6 ) 

{ 

case 0x01: 

gfreq6 = -12; 
break; 
case 0x02: 


133 







Abacus Software 


Atari ST MIDI Book 


gfreq6 =0; 
break; 
default: 

gfreq6 = 12; 
break; 

} 

switch ( fon ) 

{ 

case 0x01: 

noteoff ( 2, 0, fon + gfreq6 ); 
break; 
default: 

noteon ( 2, 64, fon + gfreq6 ); 
break; 

} 

} 

/*-on voice 7-*/ 

onv7() 

{ 

int fon, addit; 

fon = ftab7[ note7 ]; /* midi spec adjust */ 

switch ( oct7 ) 

{ 

case 0x01: 

gfreq7 = -12; 
break; 
case 0x02: 

gfreq7 = 0; 
break; 
default: 

gfreq7 = 12; 
break; 

} 

switch ( fon ) 

{ 

case 0x01: 

noteoff ( 3, 0, fon + gfreq7 ); 
break; 
default: 

noteon ( 3, 64, fon + gfreq7 ); 
break; 

} 

} 


134 





Abacus Software 


Atari ST MIDI Book 


/*- on voice 8-*/ 

onv8() 

{ 

int fon, addit; 

fon = ftab8[ note8 ]; /* midi spec adjust */ 

switch ( oct8 ) 

{ 

case 0x01: 

gfreq8 = -12; 
break; 
case 0x02: 

gfreq8 = 0; 
break; 
default: 

gfreq8 = 12; 
break; 

} 

switch ( fon ) 

{ 

case 0x01: 

noteoff ( 3, 0, fon + gfreq8 ); 
break; 
default: 

noteon ( 3, 64, fon + gfreq8 ); 
break; 

} 

} 

/* 

** This routine is the heart of the colsol 
** speaker play routine. When it is called the 
** routine receives three parameters. The sound 
** chip inside the Atari ST uses has three voices. 

** The variable vce is the voice number. The 
** variable frq is the frequency number and 
** vme is the volume. This rouine may be lifted 
** and used in your own programs. 

*/ 

/*-this routine plays a voice (vce 1-3), frequency (frq 1-96),— 

/*-and volume (vme 0-15)- 

playv ( vce, frq, vme ) 
int vce, frq, vme; 

{ 

vme = 12; 


—*/ 
—*/ 


135 








Abacus Software 


Atari ST MIDI Book 


if ( frq > 24 ) /* adjust for octave fix */ 

frq -= 24; /* dumb dumb */ 

switch ( vce ) 

{ 

case 0x01: 

if ( frq == 1 ) /* ok ok idiot fix */ 

Giaccess ( 0,0x88 ); /* dumb dumb dumb */ 

else 

Giaccess ( vme, 0x88 ); 

Giaccess ( ftune[frq], 0x80 ); 

Giaccess ( ctune[frq], 0x81 ); 
break; 
case 0x02: 

if ( frq == 1 ) /* ok ok idiot fix */ 

Giaccess ( 0,0x89 ); /* dumb dumb dumb */ 
else /* 200 */ 

Giaccess ( vme, 0x89 ); 

Giaccess ( ftune[frq], 0x82 ); 

Giaccess ( ctune[frq], 0x83 ); 

break; 
case 0x03: 

if ( frq == 1 ) /* ok ok idiot fix */ 

Giaccess ( 0,0x8a ); /* dumb dumb dumb */ 

else 

Giaccess ( vme, 0x8a ); 

Giaccess ( ftune[frq], 0x84 ); 

Giaccess ( ctune[frq], 0x85 ); 

break; 

} 

} 


/* 

** This is the Grand-daddy routine of the 
** AUTO-PLAYER. The logic is as follows: 
** 1- get a duration value for voice 1 

** 2- is it 0? 

** 3- if yes - get new note frequency 

** and duration..if no - let play 

* ★ 

** 


** 
★ ★ 
** 
★ * 
** 
** 

*/ 


4- very short wait 

5- increment measure counter 

6- update player screen 

7- check mouse & control buttons and key 

8- continue loop until done 


136 



Abacus Software 


Atari ST MIDI Book 


/*-this routine will play the notes for the demo music-*/ 


playmus() 

{ 

gpflag = 0; 
exflag = 0; 
while ( exflag == 0 ) 

{ 

if ( durl == 0 ) 
getvl(); 

if ( dur2 == 0 ) 
getv2(); 

if ( dur3 == 0 ) 
getv3 () ; 

if ( dur4 == 0 ) 
getv4 () ; 

if ( dur5 == 0 ) 
getv5(); 

if ( dur6 == 0 ) 
getv6 () ; 

if ( dur7 == 0 ) 
getv7(); 

if ( dur8 == 0 ) 
getv8 () ; 

delayl( timex, timey ); /* sets tempo */ 

durl —; 
dur2 —; 
dur3 —; 
dur4 —; 
dur5 — ; 
dur 6—; 
dur7 —; 
dur 8 —; 


first = 1; 
lmeas(); 
progdem(); 


137 






Abacus Software 


Atari ST MIDI Book 


update (); 

if ( gpflag == 255 ) /* tune over exit */ 

exflag = 1; 

9 r af_mkstate( &gr_mkmx, &gr_mkmy, &gr_mkmstate, &gr_mkkstate ); 
if ( gr_mkkstate == 4 ) /* control */ 
exflag = 1; 

} 


/* 

** This youtine calculates the measure 
** for the AUTO-PLAYER. The numbers before 
** the time signatures repsent player loop 
** numbers. These times are NOT etched in 
** stone and may change in future upgrades 
** of ST MUSIC BOX FILES. If you want to know 
** the current conversion values for the latest 
** version of ST MUSIC BOX, write Len or Dennis 
** at ABACUS and they will send you the newest 
** file information. 

*/ 

/*-calculate the measure-*/ 

/* 

** 16=2/4, 24=3/4, 32=4/4, 40=5/4 

*/ 

lmeas() 

{ 

cnt32++; 

if ( cnt32 == time ) 

{ 

cnt 32 = 0; 
meascnt++; 

} 

} 

/* 

** This is the routine which updates 
** the program change information 
** every measure. It also 
** calls a routine to update the 
** screen. This routine has to be 
** VERY fast or it would give the 
** listner a very slight music retard 
** at the beginning of each measure. 


138 





Abacus Software 


Atari ST MIDI Book 


** Of course, that would be unacceptable. 
*/ 

/*-demo of program change-*/ 


/* 

** 16=2/4, 24=3/4, 32=4/4, 40=5/4 

*/ 

progdem() 

{ 

int ttemp; 
ttemp = time; 
progcnt++; 

if ( progcnt == time ) 

{ 

progcnt = 0; 

chancnt = prog0c[ meascnt - 1 ]; 

gprog = chancnt + 1; 

chprog ( 0, chancnt ); 

chancnt = proglc[ meascnt - 1 ]; 

gprogl = chancnt + 1; 

chprog ( 1, chancnt ); 

chancnt = prog2c[ meascnt - 1 ]; 

gprog2 = chancnt + 1; 

chprog ( 2, chancnt ); 

chancnt = prog3c[ meascnt - 1 ]; 

gprog3 = chancnt + 1; 

chprog ( 3, chancnt ); 

timey = ldtmpo[ meascnt - 1 ]; 

} 

} 

/* 

** This routine grabs the notes from 
** the frequency buffers and duration 
** values from the duration buffers. 

** The function playv activates the 
** consol speaker, onvl turns on the MIDI 
** and movell updates the position of the 
** dancing notes on the screen. Note that 
** the MIDI note must be turned OFF before 
** another is turned on. That's just the 
** way it's gotta be in order for the music 
** to be clean of different machines. 

*/ 


139 




Abacus Software 


Atari ST MIDI Book 


/*-get new notes for the voices-*/ 


getvl() 

{ 

if ( dtabl[ notel ] == 0 ) 
notel++; 

durl = dtabl[ notel ]; 

if ( ftabl[ notel] == 255 || ftabl[ notel ] == 0 || vcl == 0 ) 

{ 

gpflag |= 1; 
offvl(); 

playv( 1, 1, 0 ); 
move11( 1 ); 

} 

else 

{ 

playv ( 1, ftabl[ notel ], 8 )/ 
offvl(); 

movell ( ftabl[ notel ] );/* print to screen */ 

onvl(); /* play midi */ 

notel++; 

} 

} 

getv2() 

{ 

int temp2; 

if ( dtab2[ note2 ] == 0 ) 
note2++; 

dur2 = dtab2[ note2 ]; 

if ( ftab2[ note2 ] — 255 || ftab2[ note2 ] == 0 || vc2 == 0 ) 

{ 

gpflag |= 2; 
offv2(); 
move21( 1 )/ 

} 

else 

{ 

offv2(); 

move21 ( ftab2[ note2 ] ) ;/* print to screen */ 

onv2(); /* play midi */ 

note2++; 

} 

} 

getv3() 

{ 


140 





Abacus Software 


Atari ST MIDI Book 


if ( dtab3[ note3 ] == 0 ) 
note3++; 

dur3 = dtab3[ note3 ]; 

if ( ftab3[ note3 ] == 255 || ftab3[ note3 ] == 0 || vc3 == 0 ) 

{ 

gpflag |= 4/ 
offv3(); 

playv( 2, 1, 0 ); 
move31( 1 ); 

} 

else 

{ 

playv ( 2, ftab3[ note3 ], 8 )/ 
offv3(); 

move31 ( ftab3[ note3 ] ) ;/* print to screen */ 
onv3(); /* play midi */ 

note3++; 

} 


getv4() 

{ 

if ( dtab4[ note4 ] == 0 ) 
note4++; 

dur4 = dtab4[ note4 ]; 

if ( ftab4[ note4 ] == 255 |I ftab4[ note4 ] == 0 || vc4 == 0 ) 
{ 

gpflag |= 8; 
offv4(); 
move41( 1 ); 

} 

else 

{ 

offv4(); 

move41 ( ftab4[ note4 ] ) ; /* print to screen */ 

onv4(); /* play midi */ 

note4++; 

} 


getv5() 

{ 

if ( dtab5[ note5 ] == 0 ) 
note5++; 

dur5 = dtab5[ note5 ] / 

if ( ftab5[ note5 ] == 255 || ftab5[ note5 ] == 0 || vc5 == 0 ) 
{ 


141 



Abacus Software 


Atari ST MIDI Book 


gpflag |= 16; 
offv5(); 

playv( 3, 1, 0 )/ 
move51( 1 ); 

} 

else 

{ 

playv ( 3, ftab5[ note5 ], 8 )/ 
offv5(); 

move51 ( ftab5[ note5 ] ) ; /* print to screen */ 

onv5(); /* play midi */ 

note5++; 

} 

} 

getv6() 

{ 

if ( dtab6( note6 ] == 0 ) 
note6++; 

dur6 = dtab6[ note6 ]; 

if ( ftab6[ note6 ] == 255 || ftab6 [ note6 ] ===== 0 | | vc6 == 0 ) 
{ 

gpflag |= 32; 
offv6(); 
move61( 1 ); 

} 

else 

{ 

offv6(); 

move61 ( ftab6 [ note6 ] ) ; /* print to screen */ 

onv6(); /* play midi */ 

note6++; 

} 

} 

getv7() 

{ 

if ( dtab7[ note7 ] == 0 ) 
note7++; 

dur7 = dtab7[ note7 ]; 

if ( ftab7 [ note7 ] == 255 || ftab7 [ note7 ] == 0 || vc7 == 0 ) 

{ 

gpflag |= 64; 
offv7(); 
move71( 1 ); 

} 

else 


142 



Abacus Software 


Atari ST MIDI Book 


{ 

offv7(); 

move71 ( ftab7[ note7 ] ) ; /* print to screen */ 

onv7(); /* play midi */ 

note7++; 

} 


getv8() 

{ 

if ( dtab8[ note8 ] == 0 ) 
note8++; 

dur8 = dtab8[ note8 ]; 

if ( ftab8[ note8 ] == 255 || ftab8[ note8 ] == 0 || 

{ 

gpflag |= 128; 
offv8(); 
move81( 1 ); 

} 

else 

{ 

offv8(); 

move81 ( ftab8[ note8 ] ); /* print to screen */ 

onv8(); /* play midi */ 

note8++; 

} 


/* 

** This is just a very simple delay which will 
** determine the tempo of the music. A larger delay 
** ill mean a slower tempo. 

*/ 

/*-delay which sets the tempo of the music- 

delay1 ( dl, d2 ) 
int dl, d2; 

{ 

int d3, d4; 

for ( d3 = 0; d3 < dl; d3++ ) 

{ 

for ( d4 = 0; d4 < d2; d4++ ) 

} 

} 


vc8 == 0 ) 


143 





Abacus Software 


Atari ST MIDI Book 


/* 

* reserved for future use 
*/ 

ldshow() 

{ 

} 

/* 

** end of mdrive.c file 

★ 


144 



Abacus Software 


Atari ST MIDI Book 


4.4 sets.c source code 


This file is rich, containing a variety of useful subroutines. Many of these 
routines are NOT functional in the AUTO-PLAYER and are used with the 
full ST MUSIC BOX program. They were left in the file to help us cope 
with the extraordinary time pressure we were under in order to meet our 
COMDEX demonstration deadline and we felt you might find the listing of 
these routines helpful in your own programming. 


/* sets.c */ 

/* 

** include the definition libraries here 
*/ 


#include 

#include 

#include 

tinclude 

#include 

#include 


<aiportab.h> 
<a:machine.h> 
<a:obdefs.h> 
<a:define.h> 
<a:gemdefs.h> 
<a:osbind.h> 


/* externs */ 


extern 

extern 

extern 

extern 

wcharl; 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 


int wbox, hbox, durl, dur2, dur3, port_state; 

int contrl[12], intin [256], ptsin[256], ptsout[256]; 

int intin[256], intout[256],pxy[10]; 

int newbyte[8], oldbyte[8], typedone, hboxl, wboxl, hcharl, 

int l_intin[20], l_out[128], l_ptsin[20]; 
int kreturn, i, iter; 

int ev_kreturn,gr_mkmx,gr_mkmy, groption, stylem; 
int endm,mode,set_mode; 

int set_font,handle,dummy,gr_mkmstate, gr_mkkstate,prtmem; 
int holdrez,set_effeet; 

int holdx,holdy,whesc,whescl,color_index,colorm,holdclr; 
int gr_mkresvd,intstyle,topbot,height,width,exflag; 
int widd,mull,radius; 

int begang,endang,yradius,x_boundary, y_boundary,k,kl,k2,k3,k4; 
int n,u,ab,kk,row,count,column,sp,mod,byte, j,quot,rem,demo; 
int notel, note2, note3; 

int scrold, sernew, mult, ymult, findex, fcolor,; 
int linev, lineh, linesw; 


145 



Abacus Software 


Atari ST MIDI Book 


extern int bytel, byte2, ig, sgflag,prtsw,path; 

extern int timex, timey, first, octup, octswO, octswl, octsw2; 

extern int meascnt, cnt32; 

extern int chancnt, progcnt, gfreql, gfreq2, gfreq3; 
extern long *ptrl, *ptr2, *ptr3, *ptr4, *ptr5, *ptr6; 
extern int gpsw, gptime, dblol, gvibsw, gprog; 
extern char tmpo_buffer[ 264 ], c; 

extern long logicbase,screenl,screen2,orgscrn,ltemp; 

extern char bufferl[32767],xfile_name[64]; /* main display screen */ 
char ystr[2] = { 'NO 1 , 'NO 1 }; 

/* 

* globals in this file 
*/ 

int gltemp; 
int respold =2; 

/* 

* definitions 
*/ 

#define lgdval 2 /* 2 for col & 1 for mono */ 

/* 

** sets the correct key for rest sequence 
*/ 

/* 

** when the editor was in its early stages we were using 
** the keyboard to enter notes. Rather that have the 
** user interface remember the key codes needed to enter 
** music data we decided to use simple numbers instead. 

** What this routine does is it takes the number parameter 
** calculated by the mouse assessment routine and sets 
** a global variable 'kreturn* as if the correct key had 
** been pressed. 

*/ 


ldsetr () 

{ 

switch ( respold ) 

{ 

case 0x00: 

kreturn = 0x0837; 
break; 


146 



Abacus Software 


Atari ST MIDI Book 


case 0x01: 
kreturn 
break; 
case 0x02: 
kreturn 
break; 
case 0x03: 
kreturn 
break; 
case 0x04: 
kreturn 
break; 
case 0x05: 
kreturn 
break; 

} 

} 


0x0938; 


0x0a39; 


0x0b30; 


0x0c2d; 


0x0d3d; 


/* 

* piano color key routines 
*/ 


/* 

** This function first turns OFF the color of the last piano 
** key which had been pressed and then colors the new key. 

*/ 


ldgetk () 

{ 

ldoffkeyO; /* turn key off */ 
ldonkeyO; /* turn key on */ 

} 


/* 

* turn key off to bkgd color 
*/ 

/* 

** We use the VDI function contourfill to color the keys. 
*/ 


ldoffkey() 

{ 

int isy, isx, dumdum; 


147 



Abacus Software 


Atari ST MIDI Book 


v_hide_c( handle ); 
isy = ( 298 + 16 ) / lgdval; 
dumdum = vsf_interior( handle, 1 ); 
dumdum = vswr_mode( handle, 1 ); 
dumdum = vsf_style( handle, 1 ); 
dumdum = vsf_color( handle, 0 ); 
switch ( gltemp ) 

{ 

case 0x00: 

isx = 315; 

v_contourfill( handle, isx, isy, 1 ); 
break; 
case 0x01: 

isx = 345; 

v_contourfill( handle, isx, isy, 1 ); 
break; 
case 0x02: 

isx = 368; 

v_contourfill( handle, isx, isy, 1 ); 
break; 
case 0x03: 

isx = 380; 

v_contourfill( handle, isx, isy, 1 ); 
break; 
case 0x04: 

isx = 410; 

v_contourfill( handle, isx, isy, 1 ); 
break; 
case 0x05: 

isx = 440; 

v_contourfill( handle, isx, isy, 1 ); 
break; 
case 0x06: 

isx = 470; 

v_contourfill( handle, isx, isy, 1 ); 
break; 
case 0x07: 

isx = 500; 

v_contourfill( handle, isx, isy, 1 ); 
break; 
case 0x08: 

isx = 515; 

v_contourfill( handle, isx, isy, 1 ); 
break; 
case 0x09: 

isx = 550; 

v_contourfill( handle, isx, isy, 1 ); 


148 



Abacus Software 


Atari ST MIDI Book 


break; 
case 0x0a: 

isx = 560; 

v_contourfi.ll ( handle, isx, isy, 1 ); 
break; 
case OxOb: 

isx = 590; 

v_contourfill( handle, isx, isy, 1 ); 
break; 

} 

v_show_c( handle, 1 ); 

} 


/* 

* turn on key 
*/ 


ldonkey() 

{ 


int isy, isx, dumdum; 
v_hide_c( handle ) ; 
isy = ( 298 + 16 ) / lgdval; 
dumdum = vsf_interior( handle, 1 ); 
dumdum = vswrjmode( handle, 1 ); 
dumdum = vsf_style( handle, 1 ); 
dumdum = vsf_color( handle, 2 ); 
bingl(); /* try 2 */ 

switch ( kreturn ) 

{ 


case 0x2c5a: 
case 0x2c7a: 

gltemp =0; 
isx = 315; 
v_contourfill( 
break; 

case 0xlf53: 
case 0xlf73: 
gltemp =1; 
isx = 345; 
v_contourfill( 
break; 

case 0x2d58: 
case 0x2d78: 

gltemp =2; 
isx = 368; 
v_contourfill( 
break; 


/* c */ 


handle, isx, 
/* c# */ 


handle, isx, 
/* d */ 


handle, isx. 


isy. 


isy. 


isy. 


1 ); 


1 ) ; 


l ); 


149 



Abacus Software 


Atari ST MIDI Book 


case 0x2044: /* d# */ 

case 0x2064: 

gltemp =3; 
isx = 380; 

v_contourfill( handle, isx, isy, 1 ); 
break; 

case 0x2e43: /* e */ 

case 0x2e63: 

gltemp =4; 
isx = 410; 

v_contourfill( handle, isx, isy, 1 ); 
break; 

case 0x2f56: /* f */ 

case 0x2f76: 

gltemp =5; 
isx = 440; 

v_contourfill( handle, isx, isy, 1 ); 
break; 

case 0x2247: /* f# */ 

case 0x2267: 

gltemp = 6; 
isx = 470; 

v_contourfill( handle, isx, isy, 1 ); 
break; 

case 0x3042: /* g */ 

case 0x3062: 

gltemp = 7; 
isx = 500; 

v_contourfill( handle, isx, isy, 1 ); 
break; 

case 0x2348: /* g# */ 

case 0x2368: 

gltemp = 8; 
isx = 515; 

v_contourfill( handle, isx, isy, 1 ); 
break; 

case 0x314e: /* a */ 

case 0x316e: 

gltemp = 9; 
isx = 550; 

v_contourfill( handle, isx, isy, 1 ); 
break; 

case 0x244a: /* a# */ 

case 0x246a: 

gltemp = 10; 
isx = 560; 

v contourfill( handle, isx, isy, 1 ); 


150 



Abacus Software 


Atari ST MIDI Book 


break; 

case 0x324d: /* b */ 

case 0x326d: 

gltemp = 11; 
isx = 590; 

v_contourfill( handle, isx, isy, 1 ); 
break; 

} 

v_show_c( handle, 1 ); 

} 


/* 

** binger 
*/ 

/* 

** Bing is really the wrong work hear. Short RASP sound 
** would be a better description. 

*/ 


bingl() 

{ 

int hf; 

port_state = Giaccess ( port_state, 0x07 ) ; 
n = port_state & 0xf8; 
n |= 0x38; 

Giaccess (n, 0x87 ); 

Giaccess ( 12, 0x88 ); 
setenv ( 256, 1024, 3 ); 
for ( hf = 96; hf < 1; hf— ) 

{ 

playv( 1, hf, 12 ); 

delay3(); 

delay3(); 

delay3(); 

delay3(); 

delay3(); 

delay3(); 

} 

Giaccess ( 0x00, 0x88 ) ; 

Giaccess ( port_state, 0x87 ) ; 

} 


/* 

** Here is the LONGER RASP sound. 
*/ 


151 



Abacus Software 


Atari ST MIDI Book 


bing2 () 

{ 

int hf; 

port_state = Giaccess ( port_state, 0x07 ) ; 
n = port_state & 0xf8; 
n |= 0x38; 

Giaccess (n, 0x87 ); 

Giaccess ( 12, 0x88 ); 
setenv ( 256, 1024, 3 ); 
for ( hf = 96; hf < 1; hf— ) 

{ 

playv( 1, hf, 12 ); 
delay3(); 

} 

Giaccess ( 0x00, 0x88 ) ; 

Giaccess ( port_state, 0x87 ) ; 

} 

bing25 () 

{ 

int bctr; 

for ( bctr = 0; bctr < 100; bctr++ ) 
bing2 () ; 

} 


/* 

** short delay 
*/ 


delay3 () 

{ 

int d7, d8; 

for ( d7 = 0; d7 < ( 180 * 8 ); d7 + + ); 
for ( d8 = 0; d8 < 500; d8++ ) 

} 

/* 

** Map the mouse on key press 
*/ 

/* 

** This routine would print the mouse x and mouse y 
** positions to the screen. Note that the print3d() 

** call is the one which does the actual printing. 

** The two calls are REMed out because they were used 
** only in the early stages of programming the editor. 


152 



Abacus Software 


Atari ST MIDI Book 


** They were left here if needed for upgrades. 
*/ 


mapmse() 

{ 

/* 

** print3d( gr_mkmx, 1, 1 ); 

** print3d( gr_mkmy, 6 , 1 ); 

*/ 

bing25 () ; 
bing25(); 
bing25(); 
bing25(); 

} 

/* 

* reads the mouse for note entry 

* what a pain - not so bad on 2nd thought 
*/ 

/* 

** In many ways 1 C' is such a wonderful programming 
** language!! In order to check the x & y coordinate mouse 
** location you only need to check the UPPER LEFT and LOWER 
** RIGHT of the ICON in question. See the 
** 'alter tempo' section of this function. 

** You can see that the screen location check 
** has been reduced to one line of code. Thank 
** you 'C'. 

*/ 


ldsendk() 

{ 

v_hide_c( handle ); 

graf_mkstate( &gr_mkmx, &gr_mkmy, &gr_mkmstate, &gr_mkkstate ); 

if ( gr_mkmy < 118 || gr_mkmy > 198 ) 

{ 

kreturn = 0; 

mapmseO; /* temp for mapping */ 

} 

/* 

** alter tempo 
*/ 


153 



Abacus Software 


Atari ST MIDI Book 


else if 

(gr_mkmx < 182 && gr_mkmx > 82 && gr_mkmy > 180 && gr_mkmy < 194 ) 

{ 

timey = gr_mkmx - 80; /* fix for player */ 

if ( timey >= 100 ) /* keep to under 100 */ 
timey = 99; 

tmpo_buffer[0] = tochar( timey ); 

IdstempO; /* print tempo number */ 

kreturn = 0; 

} 

/* 

** access i/o disk 
*/ 

else if 

(grjmkmx <27 && gr_mkmx > 5 && gr_mkmy > 120 && gr_mkmy < 137 ) 
kreturn = 0x4400; /* flO */ 

/* 

** access play routine 
*/ 

else if 

(gr_mkmx > 17 && grjnkmx < 61 && gr_mkmy > 149 && gr_mkmy < 165 ) 
kreturn = 0x4000; /* f6 */ 

/* 

** access midi window 
*/ 

else if 

( gr_mkmx > 80 && gr_mkmx < 100 && gr_mkmy > 160 && gr_mkmy < 172 ) 
kreturn = 0x3f00; /* f5 */ 

/* 

** set the rest 
*/ 

else if 

( gr_mkmx > 240 && gr_mkmx < 267 && gr_mkmy > 181 && gr_mkmy < 187 ) 
ldsetr(); 

/* 

** select a dotted note 
*/ 


else if 

( gr_mkmx > 134 && grjmkmx < 155 && grjnkmy > 160 && gr_mkmy < 169 ) 

{ 

bing25(); 


154 




Abacus Software 


Atari ST MIDI Book 


kreturn = 0x342e; /* . */ 

} 

/* 

** change sharp and flat 
*/ 

else if 

(gr_mkmx > 80 && gr_mkmx < 100 && grjmkmy > 145 && gr_mkmy < 153 ) 
kreturn = 0xle61; /* a */ 

/* 

** hit return key 
*/ 

else if 

(gr_mkmx > 138 && gr_mkmx < 156 && gr_mkmy > 145 && gr_mkmy < 153 ) 
kreturn = OxlcOd; /* return */ 

/* 

** backspace 
*/ 

else if 

(gr_mkmx > 192 && gr_mkmx < 213 && gr_mkmy > 145 && gr_mkmy < 154 ) 
kreturn = 0x0e08; /* backspace */ 

/* 

** whole note 
*/ 

else if 

(gr_mkmx > 241 && gr_mkmx <253 && gr_mkmy > 145 && gr_mkmy < 153 ) 

{ 

kreturn = 0x0231; /* 1 */ 

respold = 0; 

} 

/* 

** half note 
*/ 

else if 

(gr_mkmx > 256 && gr_mkmx < 267 && gr_mkmy > 145 && gr_mkmy < 153 ) 

{ 

kreturn = 0x0332; /* 2 */ 

respold = 1; 

} 

/* 

** quarter note 
*/ 

else if 

( gr_mkmx > 254 && gr_mkmx < 267 && gr_mkmy > 154 && gr_mkmy < 165 ) 

{ 


155 



Abacus Software 


Atari ST MIDI Book 


kreturn = 0x0433; /* 3 */ 

respold = 2; 

} 

/* 

** eighth note 
*/ 

else if 

(gr_mkmx > 254 && gr_mkmx < 267 && gr_mkmy > 167 && gr_mkmy < 177 ) 

{ 

kreturn = 0x0534; /* 4 */ 

respold = 3; 

} 

/* 

** sixteenth note 
*/ 

else if 

(gr_mkmx > 241 && gr_mkmx < 253 && gr_mkmy > 155 && gr_mkmy < 164 ) 

{ 

kreturn = 0x0635; /* 5 */ 

respold = 4; 

} 

/* 

** thirty second 
*/ 

else if 

(gr_mkmx > 241 && gr_mkmx < 253 && gr_mkmy > 167 && gr_mkmy < 179 ) 

{ 

kreturn = 0x0736; /* 6 */ 

respold = 5; 

} 

/* 

** change measure - down arrow key 
*/ 

else if 

(gr_mkmx > 68 && gr_mkmx < 86 && gr_mkmy > 121 && gr_mkmy < 129 ) 
kreturn = 0x5000; 

/* 

** change measure - up arrow key 
*/ 

else if 

(gr_mkmx > 94 && gr_mkmx < 111 && gr_mkmy > 120 && gr_mkmy < 130 ) 
kreturn = 0x4800; 

/* 

** change voice down - [<] key 

*/ 


156 



Abacus Software 


Atari ST MIDI Book 


else if 

(gr_mkmx > 123 && gr_mkmx < 141 && gr_mkmy > 121 && gr_mkmy < 130 ) 
kreturn = 0x333c; 

/* 

** change voice up - [>] key 
*/ 

else if 

(gr_mkmx > 150 && gr_mkmx < 169 && gr_mkmy > 121 && gr_mkmy < 130 ) 
kreturn = 0x343e; 

/* 

** change octave down - left arrow key 
*/ 

else if 

(gr_mkmx > 179 && gr_mkmx < 195 && gr_mkmy > 121 && gr_mkmy < 131 ) 
kreturn = 0x4b00; 

/* 

** change octave up - right arrow key 
*/ 

else if 

(gr_mkmx > 205 && gr_mkmx < 224 && gr_mkmy > 121 && gr_mkmy < 131 ) 
kreturn = 0x4d00; 


/* 
* ★ 

*/ 


read the drawn keyboard to pass note data 

else if ( gr_mkmx < 300 || gr_mkmx > 615 ) 

{ 

kreturn = 0; 

mapmseO; /* temp for mapping */ 

} 

else if ( gr_mkmy > 158 ) /* hopefully */ 

tckbotO; /* bottom key check */ 


else 

tcktopO; /* top key check */ 

v_show_c( handle, 1 ); 

} 


/* 

* short delay 
*/ 


delay2 () 

{ 

int d3, d4; 


157 



Abacus Software 


Atari ST MIDI Book 


for ( d3 = 0; d3 < 300; d3++ ) 

for ( d4 = 0; d4 < 100; d4++ ) 

} 

/* 

* bottom key mouse entry routine 
*/ 


/* 

** Here we used a slightly different logic to assess which 
** key the mouse pointer was over. Comparing the methods: 
** One is six and the other is half a dozen. 

** 

*/ 


tckbot () 

{ 

if ( gr_mkmx <345 ) 
ldkkl(); 

else if ( gr_mkmx < 390 ) 
ldkk3(); 

else if ( gr_mkmx < 435 ) 
ldkk5(); 

else if ( gr_mkmx < 480 ) 
ldkk6(); 

else if ( gr_mkmx < 525 ) 
ldkk8(); 

else if ( gr_mkmx < 570 ) 
ldkklO(); 

else 

ldkkl2 ()/ 

} 

/* 

* top key mouse entry routine 
*/ 

tcktop () 

{ 

if ( gr_mkmx < 330 ) 
ldkklO ; 

else if ( gr_mkmx < 360 ) 
ldkk2(); 

else if ( gr_mkmx < 375 ) 
ldkk3(); 


158 



Abacus Software 


Atari ST MIDI Book 


else if ( gr_mkmx < 405 ) 
ldkk4(); 

else if ( gr_mkmx < 435 ) 
ldkk5(); 

else if ( gr_mkmx < 465 ) 
ldkk6(); 

else if ( gr_mkmx < 495 ) 
ldkk7(); 

else if ( grjmkmx < 510 ) 
ldkk8(); 

else if ( gr_mkmx < 540 ) 
ldkk9(); 

else if ( gr_mkmx < 555 ) 
ldkklOO ; 

else if ( gr_mkmx < 585 ) 
ldkkll(); 

else 

ldkkl2(); 

} 

/★ 

* simulated mouse-keybd strokes 
*/ 

ldkkl() 

{ 

ldoffkey(); 
kreturn = 0x2c5a; 
ldonkey(); 

} 

ldkk2() 

{ 

ldoffkey(); 
kreturn = 0xlf53; 
ldonkey(); 

} 

ldkk3() 

{ 

ldof fkey () ; 
kreturn = 0x2d58; 
ldonkey(); 

} 

ldkk4() 

{ 


159 



Abacus Software 


Atari ST MIDI Book 


ldof fkey () ; 
kreturn = 0x2044; 
ldonkey() ; 

} 

ldkk5() 

{ 

ldof fkey () ; 
kreturn = 0x2e43; 
ldonkey(); 

} 

ldkk6() 

{ 

ldoffkey() ; 
kreturn = 0x2f56; 
ldonkey(); 

} 

ldkk7() 

{ 

ldof fkey () ; 
kreturn = 0x2247; 
ldonkey(); 

} 

ldkk8() 

{ 

ldoffkey (); 
kreturn = 0x3042; 
ldonkey(); 

} 

ldkk9() 

{ 

ldoffkey(); 
kreturn = 0x2348; 
ldonkey(); 

} 

ldkklOO 

{ 

ldof fkey () ; 
kreturn = 0x314e; 
ldonkey(); 

} 


160 



Abacus Software 


Atari ST MIDI Book 


ldkkll() 

{ 

ldof fkey () ; 
kreturn = 0x244a; 
ldonkey(); 

} 

ldkkl2 () 

{ 

ldoffkey(); 
kreturn = 0x324d; 
ldonkey() ; 

} 


/* 

** Here is a useful little function which will print a 
** two digit number to the screen. We use it all the 
** time. The values passed are: 

** 1) variable ..value.. 

** 2) x cursor position where number will print 
** 3) y number location where number will print 
** Note the use of register variables. Use of 
** register variables in 1 C' will speed up the code 
** sometimes by a factor of three. Since the print 
** screen routines were used in the middle of the 
** actual playing we tried to write quick code at 
** all costs. 

*/ 


int print2d ( val, xloc, yloc ) 

register int val, xloc, yloc; 

{ 

char dbuff[4]; 

dbuff[0] = '\0'; 
dbuff[1] = *\0 *; 
dbuff[0] = val / 10; 
dbuff[0] += 48; 

v_gtext(handle,width*xloc,height*yloc, dbuff); 
dbuff[0] = val % 10; 
dbuff[0] += 48; 

++xloc; 

v_gtext(handle,width*xloc,height*yloc,dbuff); 

} 


161 



Abacus Software 


Atari ST MIDI Book 


/*—print a 3 digit number—call value,xloc,yloc—*/ 

int print3d ( val3, xloc3, yloc3 ) 

register int val3, xloc3, yloc3; 

{ 

int temp3; 
char dbuff[4]; 

dbuff[0] = 1 \0 1 ; 
dbuff[1] = 1 \0 1 / 
dbuff[0] = val3 / 100; 
temp3 = val3 % 100; 
dbuff[0] += 48; 

v_gtext(handle,width*xloc3,height*yloc3, dbuff) ; 
dbuff[0] = temp3 / 10; 
dbuff[0] += 48; 

++xloc3; 

v_gtext(handle,width*xloc3,height*yloc3,dbuff); 
dbuff[0] = temp3 % 10; 
dbuff[0] += 48; 

++xloc3; 

v_gtext(handle,width*xloc3,height*yloc3,dbuff) ; 

} 


/* 

** This function call prints the screen for the AUTO-PLAYER. 
*★ 

*/ 


prtdemo() 

{ 

int ilen,xgrid, ygrid, dline; 


/* 

** first we print the numbers of the voices 
*/ 


v gtext 

( 

handle, 

v_gtext 

( 

handle 

v gtext 

( 

handle 

v_gtext 

( 

handle 

v_gtext 

( 

handle 

v gtext 

( 

handle 

v gtext 

( 

handle 


width*62,height*10,"# 1 "); 
width*62,height*12,"# 2 "); 
width*62,height*14,"# 3 "); 
width*62,height*16, "# 4 "); 
width*62,height*18,"# 5 "); 
width*62, height*20, "# 6 •'); 
width*62,height*22,"# 7 "); 


162 



Abacus Software 


Atari ST MIDI Book 


v_gtext ( handle, width*62,height*24, "# 8 "); 


/* 

** Print the TITLE and our NAMES (- for vanity, of course!) 
* ★ 

*/ 


v_gtext( handle,width*2,height*2, 

"'ST MUSIC BOX' AUTOPLAYER Filename ") ; 

v_gtext ( handle, width*2,height*3, 

"by Len Dorfman and Dennis Young (c) 1986") ; 

v_gtext(handle,width*2, height*4, 

"Pressing CONTROL will abort the song and autoload a new one."); 
v_gtext(handle,width*2, height*l, 

"From the ABACUS book ATARI ST Introduction to MIDI Programming"); 
/* 

* print the filename 
*/ 

for(dline = 50,ilen = 2; ilen < 15; ilen++,dline++ ) 

{ 

ystr[0] = xfile_name[ilen] ; 

v_gtext(handle,width*dline,height*3,ystr); 

} 

/* 

** Print the MIDI and play parameter labels\ 

*/ 


v_gtext(handle,width*2,height*6, 

"PORTAMENTO SW PORTAMENTO RATE TEMPO 

MEASURE"); 

v_gtext(handle,width*2,height*7, 

"CNTRL CD 1 CH 0 CNTRL CD 1 CH 1 

NUMBER "); 

v_gtext(handle,width*2,height*8, 

"CNTRL CD 1 CH 2 CNTRL CD 1 CH 3 "); 

v_gtext(handle,width*71,height*10,"CHAN #1"); 
v_gtext(handle,width*71,height*12,"PR. # ") ; 

v_gtext(handle,width*71,height*14,"CHAN #2"); 
v_gtext(handle,width*71,height*16,"PR. # "); 

v_gtext(handle,width*71,height*18,"CHAN #3"); 
v_gtext(handle,width*71,height*20,"PR. # ") ; 

v_gtext(handle,width*71,height*22,"CHAN #4"); 
v_gtext(handle,width*71,height*24,"PR. # "); 


VOICE 


NUMBER 


163 



Abacus Software 


Atari ST MIDI Book 


/* 

** Print the boundaries for the little animated shapes 
** which dance about the screen. 

*/ 


/* print vertical lines */ 

for (dline = 0, xgrid = 480; dline < 2; dline++,xgrid += 72) 

{ 

pxy[0] = xgrid; 

pxy[1] = 39; 

pxy[2] = xgrid; 

pxy[3] = 199; 

v_pline(handle,2,pxy); 

} 

for (dline = 0, xgrid = 560; dline < 2; dline++,xgrid += 72) 

{ 

pxy[0] = xgrid; 

pxy[1] = 39; 

pxy[2] = xgrid; 

pxy[3] = 199; 

v_pline(handle,2,pxy) ; 

} 

for (dline = 0, xgrid = 0; dline < 2; dline++,xgrid += 480) 

{ 

pxy[0] = xgrid; 

pxy[1] = 39; 

pxy[2] = xgrid; 

pxy[3] = 66; 

v_pline(handle,2,pxy); 

} 

for (dline = 0, xgrid = 0; dline < 2; dline++,xgrid += 480) 

{ 

pxy[0] = xgrid; 

pxy[1] = 71; 

pxy[2] = xgrid; 

pxy[3] = 71 + (8*16); 

v_pline(handle,2,pxy); 

} 


/* print horizontal lines in grid */ 


164 



Abacus Software 


Atari ST MIDI Book 


for (dline = 0, xgrid = 71; dline < 9; dline++, xgrid = xgrid + 16) 

{ 

pxy[0] = 0; 
pxy[l] = xgrid; 
pxy[2] = 480; 
pxy[3] = xgrid; 
v_pline(handle,2,pxy); 

} 

for (dline = 0, xgrid = 39; dline < 2; dline++, xgrid += 28) 

{ 

pxy[0] = 0; 

pxy[1] = xgrid; 

pxy[2] = 480; 

pxy[3] = xgrid; 

v_pline(handle,2,pxy); 

} 

for (dline = 0, xgrid = 39; dline < 2; dline++, xgrid += 160) 

{ 

pxy[0] = 480; 

pxy[1] = xgrid; 

pxy[2] = 552; 

pxy[3] = xgrid; 

v_pline(handle,2,pxy); 

} 

for (dline = 0, xgrid = 39; dline < 2; dline++, xgrid += 160) 

{ 

pxy[0] = 560; 
pxy[l] = xgrid; 
pxy[2] = 632; 
pxy[3] = xgrid; 
v_pline(handle,2,pxy); 

} 


} 


/* 

** reserved for future use 
*/ 


offmidi() 

{ 

} 


165 



Abacus Software 


Atari ST MIDI Book 


/* 

** This function is called at every measure beginning. 

** It was shortened in the ST MUSIC BOX program but 
** functioned just fine in the AUTO PLAYER. We think that 
** is a real endorsement for 'C' and the 68000 chip that 
** all this can take place and not delay the player 
** by too much!! 

*/ 


/*-update the midi parameters—*/ 

/*-must be el fasto code-*/ 

extern int portl, port2, port3, port4, vibl, vib2 / vib3, vib4; 

extern int gprogl, gprog2, gprog3; 


update () 

{ 


print3d ( meascnt, 73 

00 

/* measure count */ 

print2d ( gprog, 76, 

12 ); 

/* program selection 

print2d ( gprogl, 76, 

16 ) ; 

/* program selection 

print2d ( gprog2, 76, 

20 ); 

/* program selection 

print2d ( gprog3, 76, 

24 ) ; 

/* program selection 

print2d ( gptime, 42, 

6 ) ; 

/* portamento time */ 

print2d ( timey, 50, 

7 ) ; 

/* tempo — demo here 

if ( portl ! 

= 0 ) 



v_gtext 

( handle. 

width*19. 

height*6,"ON "); 

else 




v_gtext 

( handle. 

width*19. 

height*6,"OFF "); 

if ( vibl != 

0 ) 



v_gtext 

( handle. 

width*19. 

height*7,"ON "); 

else 




v_gtext 

( handle. 

width*19. 

height*7,"OFF "); 

if ( vib2 != 

0 ) 



v_gtext 

( handle. 

width*42. 

height*7,"ON "); 

else 




v_gtext 

( handle. 

width*42, 

height*7,"OFF "); 

if ( vib3 != 

0 ) 



v_gtext 

( handle. 

width*19. 

height*8,"ON "); 

else 




v_gtext 

( handle. 

width*19. 

height*8,"OFF "); 

if ( vib4 != 

0 ) 



v_gtext 

( handle. 

width*42. 

height*8,"ON "); 

else 




v_gtext 

( handle. 

width*42. 

height*8,"OFF "); 


166 






Abacus Software 


Atari ST MIDI Book 


/* 

** turn up tempo 
*/ 

/* 

** This function turns up the tempo with a key press. 
** This routine is called from the editor. 

*/ 


upttt() 

{ 

if ( timey < 99 ) 

{ 

timey++; 

tmpo_buffer[0] = tochar( timey ); 
print2d( timey, 25, 21 ); 

} 

} 

/* 

** turn down tempo 
*/ 


dnttt () 

{ 

if ( timey > 3 ) 

{ 

timey—; 

tmpojouffer[0] = tochar( timey ); 
print2d( timey, 25, 21 ); 

} 

} 

/* 

** end of sets.c 
*/ 


167 



Abacus Software 


Atari ST MIDI Book 


4.5 btdata.c source code 


This file holds the data for the screen icons of the ST MUSIC BOX. The 
data is in two forms: 1) x & y coordinate information for a VDI 'v pline' 
call; and 2) the 'char' data which will be directly written to the screen. 

The ST MUSIC BOX AUTO-PLAYER is designed to work in the medium 
resolution color mode. When bytes (called chars in 'C') are written to the 
screen, the way that they are written will determine their color. 

In real life Len is far more than a black and white person, but when 
contributing his input to the design of the editor screen he screamed loud 
and clear that the screen should be black and white. Some at Xlent 
commented that to use only black and white on a beautiful color RGB 
monitor was a crime. No matter to Len, he felt that long hours at the 
monitor screen should be spend with as little eyestrain as possible. After 
jiggling the colors about we decided to leave the editor screen black and 
white, with the colors of the selected keys being highlighted in red. 

Following the black and white theme we had to design the icon bit maps to 
appear in black and white. The reality of writing the code to have the icons 
appear black and white is easy, but the underlying reasons with roots in the 
bit plane structure of the color monitor isn’t so easy. First we'll discuss the 
bit planes structure of the medium resolution mode and then move on to the 
byte arrangement. 

The visible screen is made up of RAM (Random Access Memory). The 
BITS of the BYTES in the screen RAM determine what pixels (or picture 
elements) of the screen will be turned on. The BYTE arrangement is 
unique to each screen resolution mode. We will briefly discuss the BYTE 
arrangement of the monochrome and medium resolution modes. 

In the high resolution monochrome mode, the screen resolution is 640 
pixels wide by 400 pixels high. Each pixel width increment may be called 
a column and each pixel increment high may be called a row. Every row of 
640 pixel columns is composed of 80 BYTES. Recalling the definition of 
BYTES from chapter 2, we know that each BYTE is made up of 8 BITS. 
Each of a BYTES 8 BITS can hold a 1 or a 0. It is simple to see that 80 
BYTES times 8 BITS yields 640 pixels. If you surmised that every BIT in 
the monochrome mode equals a screen pixel you are correct! 


168 



Abacus Software 


Atari ST MIDI Book 


MONOCHROME SCREEN BYTE ARRANGEMENT 


-80 bytes- 
640 pixels 


Monochrome mode is composed of an 80 BYTE row and there are 400 
rows. The screen RAM required for the monochrome screen is 80 BYTES 
times 400 rows = 32000 BYTES. 

The medium resolution mode screen BYTE arrangement is different from 
monochrome screen BYTE arrangement. In the medium resolution mode 
there are 4 colors available for each pixel. In the monochrome mode there 
were two colors available for each pixel. Four colors per pixel are permitted 
because the ST's operating system will assign TWO BITS for each pixel in 
the medium resolution mode. 


MEDIUM RESOLUTION COLOR BIT OPTIONS 

COLOR 

BIT PATTERN 

0 

00 

1 

11 

2 

01 

3 

10 


If you are familiar with the old Atari 130XE BIT arrangement it would be 
reasonable to assume that the two BITS required to generate the four color 
pixel would be located within the same BYTE. Unfortunately, that is not 
the case. The Atari ST uses a standard method of using the screen RAM to 
enable color choice called BIT PLANES. 

The medium resolution color mode's screen pixel resolution is 640 by 200. 
Each row of BYTES contains 160 bytes. The total screen RAM required by 
the medium resolution color mode is 160 BYTES times 200 rows = 32000 
BYTES. The same is required by the monochrome screen. 


169 











Abacus Software 


Atari ST MIDI Book 


MEDIUM RESOLUTION BYTE/BIT ARRANGEMENT 

Byte 1 

Byte 

2 


Byte 

3 


Byte 

4 


BIT 

BIT 



BIT 



BIT 



7 6 5 4 3 2 

10 7 6 

5 4 3 

2 1 

0 7 6 

5 4 

3 2 

10 7 

6 5 

4 3 2 

1 0 

SCREEN PIXEL LOCATION 







X=0,y=0 

uses 

BIT 

7 

BYTE 

l 

Sc 

BIT 

7 

BYTE 

3 

x=l,y=0 

uses 

BIT 

6 

BYTE 

l 

Sc 

BIT 

6 

BYTE 

3 

x=2,y=0 

uses 

BIT 

5 

BYTE 

i 

Sc 

BIT 

5 

BYTE 

3 

x=3,y=0 

uses 

BIT 

4 

BYTE 

l 

Sc 

BIT 

4 

BYTE 

3 

x=4,y=0 

uses 

BIT 

3 

BYTE 

i 

Sc 

BIT 

3 

BYTE 

3 

x=5,y=0 

uses 

BIT 

2 

BYTE 

i 

Sc 

BIT 

2 

BYTE 

3 

x=6,y=0 

uses 

BIT 

1 

BYTE 

l 

Sc 

BIT 

1 

BYTE 

3 

x=7,y=0 

uses 

BIT 

0 

BYTE 

l 

Sc 

BIT 

0 

BYTE 

3 

x=8,y=0 

uses 

BIT 

7 

BYTE 

2 

Sc 

BIT 

7 

BYTE 

4 

x=9,y=0 

uses 

BIT 

6 

BYTE 

2 

Sc 

BIT 

6 

BYTE 

4 

x=10,y=0 

uses 

BIT 

5 

BYTE 

2 

Sc 

BIT 

5 

BYTE 

4 

x=ll,y=0 

uses 

BIT 

4 

BYTE 

2 

Sc 

BIT 

4 

BYTE 

4 

x=12,y=0 

uses 

BIT 

3 

BYTE 

2 

Sc 

BIT 

3 

BYTE 

4 

x=13,y=0 

uses 

BIT 

2 

BYTE 

2 

Sc 

BIT 

2 

BYTE 

4 

x=14,y=0 

uses 

BIT 

1 

BYTE 

2 

Sc 

BIT 

1 

BYTE 

4 

x=15,y=0 

uses 

BIT 

0 

BYTE 

2 

Sc 

BIT 

0 

BYTE 

4 


You can see that the color for pixel location x=0 & y=0 is determined by the 
BIT 7 values from BYTES 1 & 3. The BITS ARE NOT CONTIGUOUS 
as per the arrangement in the Atari 130XE home computer. Note that the 
pixel locations all have the y=0 value. To write to the pixels directly below 
BYTE 1 you would need to add the value of 160 to BYTE l's address. 
When you see the code in file 'btdata. c ' you will see how easy it is to 
write BYTES below another in the 'C' programming language. 


170 






Abacus Software 


Atari ST MIDI Book 


The 'C' source code for 'btdata. c'. 


/* 

** btdata.c 
*/ 

extern long orgscrn, screenl; 

extern int time, timex, timey, handle, dummy, height, width; 
/* 

** boundary for changing note 
★ ★ 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 

int pxynote[16] = { 

238+4,120, 

266+4,120, 

266+4,138, 

238+4,138, 

238+4,120, 

237+4,121, 

237+4,139, 

265+4,139 } ; 

/* 

** boundary for T:00 info 
** 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 


int pxyt00[16] = { 

179,160, 

179.170, 
215+4,170, 
215+4,160, 

179.160, 

178.161, 

178.171, 
214+4,171 } ; 


171 



Abacus Software 


Atari ST MIDI Book 


/* 

** boundary for the tempo information 
** 

** this array of integers are to be used by a 


★ * 

VDI v_pline call. 

*/ 



int 

pxytemp[16] = { 


56, 

180, 


56, 

194, 


214 

,194, 


214 

/180, 


56, 

180, 


55, 

181, 


55, 

195, 


213 

/195 } ; 


/* 

** number 2 for time sig data 
** 

** this array of integers is written directly into 
** screen memory 
*/ 

char sig2dat[13][4] = { 

255,0,255,0, 

34,0,34,0, 

65,0,65,0, 

1 / 0 , 1 , 0 , 

1 / 0 , 1 , 0 , 

2 , 0 , 2 , 0 , 

255,0,255,0, 

8 , 0 , 8 , 0 , 

16,0,16,0, 

32,0,32,0, 

92,0,92,0, 

227,0,227,0, 

255,0,255,0 } ; 

/* 

** #3 time sig data 

★ ★ 

** this array of integers is written directly into 
** screen memory 
*/ 


172 



Abacus Software 


Atari ST MIDI Book 


char sig3dat[13][4] = { 
255,0,255,0, 
34,0,34,0, 
65,0,65,0, 

3,0,3,0, 

6 , 0 , 6 , 0 , 

57,0,57,0, 

255,0,255,0, 

1 , 0 , 1 , 0 , 

1 , 0 , 1 , 0 , 

2 , 0 , 2 , 0 , 

4,0,4,0, 

24,0,24,0, 
255,0,255,0 } ; 


/* 

** #4 time sig data 

*★ 

** this array of integers is written directly into 
** screen memory 
*/ 

char sig4dac[13][4] = ( 

255,0,255,0, 

12 , 0 , 12 , 0 , 

20 , 0 , 20 , 0 , 

20 , 0 , 20 , 0 , 

36,0,36,0, 

75,0,75,0, 

255,0,255,0, 

232,0,232,0, 

8 , 0 , 8 , 0 , 

8 , 0 , 8 , 0 , 

16,0,16,0, 

16,0,16,0, 

255,0,255,0 } ; 

/* 

** #5 time sig data 

** 

** this array of integers is written directly into 
** screen memory 
*/ 


char 


sig5dat[13][4] = { 
255,0,255,0, 
28,0,28,0, 


173 



Abacus Software 


Atari ST MIDI Book 


224,0,224,0, 

128,0,128,0, 

142,0,142,0, 

177,0,177,0, 

255,0,255,0, 

2 , 0 , 2 , 0 , 

4,0,4,0, 

4,0,4,0, 
24,0,24,0, 
96,0,96,0, 
255,0,255,0 } ; 


/* 

** turtle icon data 

** this array of integers is written directly into 
** screen memory 
*/ 

char turcon[11][4] = { 

0 , 0 , 0 , 0 , 

0, 0, 0, 0, 

14,0,14,0, 

57,128,57,128, 

115,192,115,192, 

103,204,103,204, 

255,252,255,252, 

255.224.255.224, 

32,64,32,64, 

48, 96, 48, 96, 

0 , 0 , 0,0 } ; 

/* 

** rabbit icon 
** 

** this array of integers is written directly into 
** screen memory 
*/ 

char rabcon[11][4] = { 

0 , 0 , 0 , 0 , 

12 , 0 , 12 , 0 , 

8 , 0 , 8 , 0 , 

16,0,16,0, 

35.224.35.224, 

117,84,117,84, 

126,168,126,168, 


174 



Abacus Software 


Atari ST MIDI Book 


37,88,37,88, 
3,240,3,240, 
2,16,2,16, 
4,32,4,32 }; 


/* 

** disk icon data 
** 

** this array of integers is written directly into 
** screen memory 
*/ 


char dicon[20][8] = { 

199.255.199.255.255.252.255.252, 
204,0,204,0,0,4,0,4, 
204,0,204,0,0,4,0,4, 
204,255,204,255,255,132,255,132, 
204,24 0,204,2 4 0,3, 196,3, 196, 

204,240,204,240,115,228,115,228, 

204,240,204,240,115,228,115,228, 

204.240.204.240.115.228.115.228, 

204.240.204.240.3.228.3.228, 

204.255.204.255.255.228.255.228, 

204,255,204,255,255,228,255,228, 

204,255,204,255,255,228,255,228, 

204,255,204,255,255,228,255,228, 

204,255,204,255,255,228,255,228, 

204,255,204,255,255,228,255,228, 

204,255,204,255,255,228,255,228, 
204,0,204,0,0,4,0,4, 
204,0,204,0,0,4,0,4, 

207.255.207.255.255.252.255.252, 
207,255,207,255,255,248,255,248 } ; 


/* 

** player icon 
*★ 

** this array of integers is written directly into 
** screen memory 
*/ 


char playicon[20][12] = { 

127,255,127,255,255,255,255,255,255,255,255,255, 
192,0, 192,0, 0, 0, 0, 0, 0, 1, 0, 1, 

192,0, 192,0, 0, 0, 0, 0, 0, 1, 0,1, 

192,0,192,0,0,7,0,7,249,1,249,1, 

192,192,192,192,1,124,1,124,9,1,9,1, 


175 



Abacus Software 


Atari ST MIDI Book 


192,192,192,192,30,0,30,0,4,129,4,129, 

192, 192,192, 192,22 4,0,224,0, 4,12 9, 4, 129, 

192,195, 192,195, 0, 0,0, 0,2, 65,2, 65, 

192,236, 192,236, 14,130,14,130, 42, 65, 42, 65, 

192,232,192,232,14,135,14,135,58,65,58,65, 

192,236, 192,236, 8,239, 8,239, 14 6, 65,14 6, 65, 

192,195, 192, 195, 0, 0,0, 0,2, 65,2, 65, 

192,192,192, 192,224,0,224,0, 4, 12 9, 4, 12 9, 
192,192,192,192,30,0,30,0,4,129,4,129, 

192,192,192,192,1, 124,1,124, 9, 1, 9, 1, 
192,0,192,0,0,7,0,7,249,1,249,1, 

192,0,192,0,0,0,0,0,0,1,0,1, 
192,0,192,0,0,0,0,0,0,1,0,1, 

255,255,255,255,255,255,255,255,255,255,255,255, 
255,255,255,255,255,255,255,255,255,254,255,254 } ; 


/* 

** music icon data 
★ * 

** this array of integers is written directly into 
** screen memory 
*/ 


char muicon[45][8] = { 

127.255.127.255.255.252.255.252, 
192,1,192,1,0,4,0,4, 

192,1,192,1,0,4,0,4, 

195,129,195,129,3,132,3,132, 

204,97,204,97,15,228,15,228, 

204,97,204,97,15,228,15,228, 

204,97,204,97,15,228,15,228, 
195,129,195,129,3,132,3,132, 
192,1,192,1,0,4,0,4, 
192,1,192,1,0,4,0,4, 

255.255.255.255.255.252.255.252, 
192,1,192,1,0,4,0,4, 
192,1,192,1,0,4,0,4, 

199, 129, 199, 129, 6, 4,6, 4, 

198.65.198.65.6.4.6.4, 

198.33.198.33.6.4.6.4, 

199.129.199.129.6.4.6.4, 

198.65.198.65.6.4.6.4, 

198.33.198.33.6.4.6.4, 

198.1.198.1.6.4.6.4, 

192, 1, 192,1, 0, 4,0, 4, 
192,1,192,1,0,4,0,4, 

255,255,255,255,255,252,255,252, 


176 



Abacus Software 


Atari ST MIDI Book 


192,1,192,1,0,4,0,4, 

192,1,192,1,0,4,0,4, 

19 9, 12 9, 199, 12 9, 7, 132,7, 132, 

198, 65,198,65, 6, 68, 6, 68, 
198,33,198,33,6,36,6,36, 

199, 129, 199, 129, 6, 4,6, 4, 

198, 65, 198, 65, 6, 4, 6, 4, 

198,33,198,33,6,4,6,4, 

199, 129, 199, 129, 6, 4,6, 4, 

198, 65, 198, 65, 6, 4, 6, 4, 

198.33.198.33.6.4.6.4, 
192,1,192,1,0,4,0,4, 
192,1,192,1,0,4,0,4, 
255,255,255,255,255,252,255,252, 
192,0,192,0,0,4,0,4, 
192,0,192,0,0,4,0,4, 

192.15.192.15.240.4.240.4, 

192,15, 192,15,24 0, 4,2 4 0, 4, 
192,0,192,0,0,4,0,4, 
192,0,192,0,0,4,0,4, 
255,255,255,255,255,252,255,252, 
255,255,255,255,255,248,255,248 }; 


/* 

** outline the letter S - 8 points - 
** 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 

int pxys[16] = { 

80.144, 

102.144, 

102.154, 

80.154, 

80.144, 

79.145, 

79.155, 

101,155 }; 

/* 

** outline the natural - 8 points - 
★ * 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 


177 



Abacus Software 


Atari ST MIDI Book 


int pxynat[16] = { 

80,144+16, 

102,144+16, 

102,154+18, 

80,154+18, 

80,144+16, 

79,145+16, 

79,155+18, 
101,155+18 }; 


/* 

** draw the dot icon 
** 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 


int ldotdraw[12] = { 
90+56,148+16, 
92+56,148+16, 
93+56,149+16, 
89+56,149+16, 
90+56,150+16, 
92+56,150+16 } ; 


/* 

** drawnto natural symbol 
★ ★ 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 


int natdraw[10] = { 
82,152+16, 
82,146+16, 
91,152+16, 

100,146+16, 
100,152+16 } ; 


/* 

** outline the letter R - 8 points - 
** 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 


178 



Abacus Software 


Atari ST MIDI Book 


int pxyr[16] = { 

80+56,144, 
102+56,144, 
102+56,154, 
80+56,154, 
80+56,144, 
79+56,145, 
79+56,155, 
101+56,155 }; 


/* 

** outline the dot - 8 points - 
★ ★ 

** this array of integers are to be used by a 
** VDI vjpline call. 

*/ 


int pxydot[16] = { 

80+56,144+16, 
102+56,144+16, 
102+56,154+16, 
80+56,154+16, 
80+56,144+16, 
79+56,145+16, 
79+56,155+16, 
101+56,155+16 }; 


/* 

** outline the letter B - 8 points - 
** 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 


int pxyb[16] = { 

80+112,144, 

102+112,144, 

102+112,154, 

80+112,154, 

80+112,144, 

79+112,145, 

79+112,155, 

101+112,155 }; 


179 



Abacus Software 


Atari ST MIDI Book 


/* 

** outline for the letters U & B - 8 points - 
★ ★ 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 

int pxyub[16] = { 

4.176, 

42.176, 

42.194, 

4.194, 

4.176, 

3.177, 

3.195, 

41,195 }; 

/* 

** outline for the large box - 8 points - 
** 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 


int pxybb[16] = { 

1,118, 

286,118, 

286.198, 

1.198, 

1,118, 
0,119, 
0,199, 
285,199 }; 


/* 

** outline for M box - 17 points - 
* ★ 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 


int pxymt[34] = { 

67.120, 

114.120, 

114.131, 

106.131, 

106.132, 


180 



Abacus Software 


Atari ST MIDI Book 


113.132, 

106.132, 

106.138, 

73.138, 

73.131, 

67.131, 

67.120, 

66 . 121 , 

66.132, 

72.132, 

72.139, 
105, 139 }; 


/* 

** outline for V box - 17 points - 
** 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 


int pxymv[34] = { 
67+56,120, 
114+56,120, 
114+56,131, 
106+56,131, 
106+56,132, 
113+56,132, 
106+56,132, 
106+56,138, 
73+56,138, 
73+56,131, 
67+56,131, 
67+56,120, 
66+56,121, 
66+56,132, 
72+56,132, 
72+56,139, 
105+56,139 }; 


/* 

** outline for 0 box - 17 points - 
* ★ 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 


181 



Abacus Software 


Atari ST MIDI Book 


int pxymo[34] = { 

67+112,120, 

114+112,120, 

114+112,131, 

106+112,131, 

106+112,132, 

113+112,132, 

106+112,132, 

106+112,138, 

73+112,138, 

73+112,131, 

67+112,131, 

67+112,120, 

66+112,121, 

66+112,132, 

72+112,132, 

72+112,139, 

105+112,139 }; 


/* 

** bass and cleff data 
*★ 

** this array of integers is written directly into 
** screen memory 
*/ 


char ldcleff[65][4] = { 
0,96,0,96, 
0,224,0,224, 
0,144,0,144, 
1,152,1,152, 

1,152,1,152, 

3,24,3,24, 

3,24,3,24, 

3,24,3,24, 

255,255,255,255, 

3.48.3.48, 

1.48.1.48, 
0,224,0,224, 
0,192,0,192, 

1,128,1,128, 
255,255,255,255, 

7.128.7.128, 

14.128.14.128, 

28.128.28.128, 

24,64,24,64, 


182 



Abacus Software 


Atari ST MIDI Book 


48,64,48,64, 

255,255,255,255, 

99.112.99.112, 

102 , 88 , 102 , 88 , 

68,76, 68, 76, 

68.44.68.44, 

68,36, 68,36, 

255,255,255,255, 

36, 36,36,36, 

34.44.34.44, 

16,40,16,40, 

8.48.8.48, 

7,224,7,224, 

255,255,255,255, 

0,16,0,16, 

2,16,2,16, 

7,16,7,16, 

15.48.15.48, 

14.48.14.48, 

7.224.7.224, 

3.192.3.192, 

0 , 0 , 0 , 0 , 

0 , 0 , 0 , 0 , 

0 , 0 , 0 , 0 , 

0 , 0 , 0 , 0 , 

255,255,255,255, 

11.192.11.192, 

16.224.16.224, 

32,230,32,230, 

40.118.40.118, 

44.112.44.112, /* either 4 or 44?? */ 

255,255,255,255, 

28.112.28.112, 

24.118.24.118, 

0,230,0,230, 

0,224,0,224, 

0,192,0,192, 

255,255,255,255, 

0,192,0,192, 

1,128,1,128, 

3,0,3,0, 

6 , 0 , 6 , 0 , 

8 , 0 , 8 , 0 , 

255,255,255,255, 

32,0,32,0, 

64,0,64,0 } ; 


183 



Abacus Software 


Atari ST MIDI Book 


/* 

** define 1 for mono and 2 for med rez col 
*/ 


#define blgdval 2 


/* 

** data for piao keyboard shape 
** 

** this array of integers are to be used by a 
** VDI v_pline call. 

*/ 

int bkdat [100] = { 


435, 

( 

380 

+ 

16 

) 

/ 

blgdval. 

435, 

( 

220 

+ 

16 

) 

/ 

blgdval. 

405, 

( 

220 

+ 

16 

) 

/ 

blgdval. 

405, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

390, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

390, 

( 

380 

+ 

16 

) 

/ 

blgdval. 

390, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

375, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

375, 

( 

220 

+ 

16 

) 

/ 

blgdval. 

360, 

( 

220 

+ 

16 

) 

/ 

blgdval. 

360, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

345, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

345, 

( 

380 

+ 

16 

) 

/ 

blgdval. 

345, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

330, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

330, 

( 

220 

+ 

16 

) 

/ 

blgdval. 

300, 

( 

220 

+ 

16 

) 

/ 

blgdval. 

300, 

( 

380 

+ 

16 

) 

/ 

blgdval. 

480, 

( 

380 

+ 

16 

) 

/ 

blgdval. 

480, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

465, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

465, 

( 

220 

+ 

16 

) 

/ 

blgdval. 

495, 

( 

220 

+ 

16 

) 

/ 

blgdval. 

495, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

480, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

480, 

( 

380 

+ 

16 

) 

/ 

blgdval. 

525, 

( 

380 

+ 

16 

) 

/ 

blgdval. 

525, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

510, 

( 

300 

+ 

16 

) 

/ 

blgdval. 

510, 

{ 

220 

+ 

16 

) 

/ 

blgdval, 

540, 

( 

220 

+ 

16 

) 

/ 

blgdval, 

540, 

( 

300 

+ 

16 

) 

/ 

blgdval, 

525, 

( 

300 

+ 

16 

) 

/ 

blgdval, 


184 



Abacus Software 


Atari ST MIDI Book 


525, 

( 

380 

+ 

16 

) 

/ 

blgdval 

570, 

( 

380 

+ 

16 

) 

/ 

blgdval 

570, 

( 

300 

+ 

16 

) 

/ 

blgdval 

555, 

( 

300 

+ 

16 

) 

/ 

blgdval 

555, 

( 

220 

+ 

16 

) 

/ 

blgdval 

585, 

( 

220 

+ 

16 

) 

/ 

blgdval 

585, 

( 

300 

+ 

16 

) 

/ 

blgdval 

570, 

( 

300 

+ 

16 

) 

/ 

blgdval 

570, 

( 

380 

+ 

16 

) 

/ 

blgdval 

615, 

( 

380 

+ 

16 

) 

/ 

blgdval 

615, 

( 

220 

+ 

16 

) 

/ 

blgdval 

330, 

}; 

( 

220 

+ 

16 

) 

/ 

blgdval 


/* 

** draw the piano keyboard for editor 


bones() 

{ 

int lddx, ldpxy4 
v_pline( handle, 
v_pline( handle, 
v_pline( handle, 
v_pline( handle, 
v_pline( handle, 
v_pline( handle, 
v_pline( handle, 
v_pline( handle, 
v_pline( handle, 
v_pline( handle, 
ldtrebf(); 
ldmuic(); 
lddicon(); 
ldturab(); 
ldplicon(); 
v_gtext( handle, 
v_pline( handle, 
ldstemp(); 
v_pline( handle, 
v_pline( handle, 
v_pline( handle, 
v_pline( handle, 
v_pline( handle, 
ldpxy4[l] = 180; 
ldpxy4[3] = 194; 


[4]; 

45, bkdat ); 

8,pxyub ); 

8,pxybb ); 

8,pxys ); 

8,pxyr ); 

8,pxyb ); 

8,pxynote ); 

17,pxymt ); 

17,pxymv ); 

17,pxymo ); 

/* print bass and treble */ 

/* print the music icons */ 

/* print the disk icon */ 

/* print turtle and rabbit */ 

/* print player icon */ 
width*23, height*21, "T: "); 

8, pxytOO ); /* box around T:00 */ 

/* print tempo # */ 

8, pxytemp ); 

5, natdraw ); 

8, pxynat ); 

8, pxydot ); 

6, ldotdraw ); 


185 



Abacus Software 


Atari ST MIDI Book 


for ( lddx = 82; lddx <= 184; lddx += 2 ) 

{ 

ldpxy4[0] = lddx; 
ldpxy4[2] = lddx; 
v_pline( handle, 2, ldpxy4 ); 

} 

switch ( time ) 

{ 

case 16: 

ldti24(); /* time is 2/4 */ 

break; 
case 24: 

ldti340; 
break; 
case 32: 

ldti4 4 () ; 
break; 
case 40: 

ldti54 () ; 
break; 

} 

graf_mouse( 3, &dummy ); 
v_show_c( handle, 1 ); 

} 


/* 

** show the time signature for 2/4 
*★ 

** This routine write byte values directly into screen memory 
*/ 


ldti240 

{ 

int ldrow, ldcol, ldl; 

char *ldptr, ldcl, ldc2; 

ldptr = screenl + ( 39 * 160 ) + 16; 

/* 39 = row */ 

for ( ldl « 0, ldrow = 0; ldrow < 13; ldl += 160, ldrow++ ) 

for ( ldcol = 0; ldcol < 4; ldcol++ ) 

{ 

ldcl = sig2dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) I ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

ldptr = screenl + ( 51 * 160 ) +16; 

for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, ldrow++ ) 

for ( ldcol = 0; ldcol < 4; ldcol++ ) 


186 



Abacus Software 


Atari ST MIDI Book 


{ 

ldcl = sig4dat[ldrow][ldcol]/ 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

ldptr = screenl + ( 75 * 160 ) + 16; 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 

for ( ldcol = 0; ldcol <4; ldcol++ ) 

{ 

ldcl = sig2dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

ldptr = screenl + ( 87 * 160 ) + 16; 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 

for ( ldcol = 0; ldcol <4; ldcol++ ) 

{ 

ldcl = sig4dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

} 

/* 

** show the time signature for 3/4 
*/ 


ldti34 () 

{ 

int ldrow, ldcol, ldl; 
char *ldptr, ldcl, ldc2; 
ldptr = screenl + ( 39 * 160 ) + 16; 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 

for ( ldcol = 0; ldcol <4; ldcol++ ) 

{ 

ldcl = sig3dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

ldptr = screenl + ( 51 * 160 ) + 16; 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 

for ( ldcol =0; ldcol < 4; ldcol++ ) 

{ 

ldcl = sig4dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 


ldrow++ ) 


ldrow++ ) 


ldrow++ ) 


ldrow++ ) 


187 



Abacus Software 


Atari ST MIDI Book 


} 

ldptr = screenl + ( 75 * 160 ) + 16/ 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 

for ( ldcol = 0; ldcol <4; ldcol++ ) 

{ 

ldcl = sig3dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) I ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

ldptr = screenl + ( 87 * 160 ) +16; 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 

for ( ldcol = 0; ldcol < 4; ldcol++ ) 

{ 

ldcl = sig4dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) I ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

} 


/* 

** show the time signature for 4/4 
*/ 

ldti44 () 

{ 

int ldrow, ldcol, ldl; 
char *ldptr, ldcl, ldc2; 
ldptr = screenl + (39* 160) +16; 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 

for ( ldcol = 0; ldcol < 4; ldcol++ ) 

{ 

ldcl = sig4dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) I ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

ldptr = screenl + ( 51 * 160 ) +16; 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 

for ( ldcol = 0; ldcol < 4; ldcol++ ) 

{ 

ldcl = sig4dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) I ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

ldptr = screenl + ( 75 * 160 ) + 16; 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 

for ( ldcol = 0; ldcol < 4; ldcol++ ) 


ldrow++ ) 


ldrow++ ) 


ldrow++ ) 


ldrow++ ) 


ldrow++ ) 


188 



Abacus Software 


Atari ST MIDI Book 


{ 

ldcl = sig4dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

ldptr = screenl + ( 87 * 160 ) + 16; 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 
for ( ldcol =0; ldcol < 4; ldcol++ ) 

{ 

ldcl = sig4dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

} 

/* 

** show the time signature for 5/4 
*/ 


ldti54 () 

{ 

int ldrow, ldcol, ldl; 
char *ldptr, ldcl, ldc2; 
ldptr - screenl + ( 39 * 160 ) + 16; 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 

for ( ldcol = 0; ldcol < 4; ldcol++ ) 

{ 

ldcl = sig5dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

ldptr = screenl + ( 51 * 160 ) + 16; 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 

for ( ldcol =0; ldcol < 4; ldcol++ ) 

{ 

ldcl = sig4dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

ldptr = screenl + ( 75 * 160 ) + 16; 
for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, 

for ( ldcol = 0; ldcol < 4; ldcol++ ) 

{ 

ldcl = sig5dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 


ldrow++ ) 


ldrow++ ) 


ldrow++ ) 


ldrow++ ) 


189 



Abacus Software 


Atari ST MIDI Book 


} 

ldptr = screenl + ( 87 * 160 ) + 16/ 

for ( ldl = 0, ldrow = 0; ldrow < 13; ldl += 160, ldrow++ ) 
for ( ldcol = 0; ldcol < 4; ldcol++ ) 

{ 

ldcl = sig4dat[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

} 


/* 

** show the tempo held in timey 
*/ 

ldstemp() 

{ 

print2d( timey, 25, 21); 

} 


/* 

** draw the treble and bass cleffs 
*/ 


ldtrebf() 

{ 

int ldrow, ldcol, ldl; 

char *ldptr, ldcl, ldc2; 

ldptr = screenl + ( 31 * 160 ) + 8; 

for ( ldl = 0, ldrow = 0; ldrow < 65; ldl += 160, ldrow++ ) 

{ 

for ( ldcol = 0; ldcol < 4; ldcol++ ) 

{ 

ldcl = ldcleff[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

} 

switch ( time ) 

{ 

case 16: 

ldti24(); /* time is 2/4 */ 

break; 
case 24: 

ldti34 () ; 
break; 


190 



Abacus Software 


Atari ST MIDI Book 


case 32: 

ldt i 4 4 () ; 
break; 
case 40: 

ldti54 () ; 
break; 

} 

} 


/* 

** draw the music icons 
*/ 

ldmuic() 

{ 

int ldrow, ldcol, ldl; 
char *ldptr, ldcl, ldc2; 
ldptr = screenl + ( 144 * 160 ) + 60; 
for ( ldl = 0, ldrow = 0; ldrow < 45; ldl += 160, 
for ( ldcol = 0; ldcol < 8; ldcol++ ) 

{ 

ldcl = muicon[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

} 

/* 

** draw the disk icon 
*/ 

lddicon() 

{ 

int ldrow, ldcol, ldl; 
char *ldptr, ldcl, ldc2; 
ldptr = screenl + ( 120 * 160 ) ; 

for ( ldl = 0, ldrow = 0; ldrow < 20; ldl += 160, 
for ( ldcol =0; ldcol < 8; ldcol++ ) 

{ 

ldcl = dicon[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

} 


ldrow++ ) 


ldrow++ ) 


191 



Abacus Software 


Atari ST MIDI Book 


/* 

** draw the player icon 
*/ 

ldplicon() 

{ 

int ldrow, ldcol, ldl; 

char *ldptr, ldcl, ldc2; 

ldptr = screenl + ( 148 * 160 ) +4/ 

for ( ldl = 0, ldrow =0/ ldrow < 20; ldl += 160, ldrow++ ) 
for ( ldcol =0; ldcol < 12; ldcol++ ) 

{ 

ldcl = playicon[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

} 

/* 

** draw the rabbit and turtle icons 
*/ 

ldturab() 

{ 

int ldrow, ldcol, ldl; 

char *ldptr, ldcl, ldc2; 

ldptr = screenl + ( 181 * 160 ) + 16; 

for ( ldl = 0, ldrow = 0; ldrow < 11; ldl += 160, ldrow++ ) 

for ( ldcol = 0; ldcol <4; ldcol++ ) 

{ 

ldcl = turcon[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) | ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

ldptr = screenl + ( 181 * 160 ) + 48; 

for ( ldl = 0, ldrow = 0; ldrow < 11; ldl += 160, ldrow++ ) 

for ( ldcol = 0; ldcol < 4; ldcol++ ) 

{ 

ldcl = rabcon[ldrow][ldcol]; 

ldc2 = *( ldptr + ldl + ldcol ) I ldcl; 

*( ldptr + ldl + ldcol ) = ldc2; 

} 

} 

/* 

** end of btdata.c 
*/ 


192 



Abacus Software 


Atari ST MIDI Book 


4.6 interf .c source code 


This file contains the information for the file structure of the AUTO 
PLAYER and also the ST MUSIC BOX'S editor. We offer this information 
to the public so any parties interested in writing utility programs which will 
link differing MIDI programs will be able to do so. It is our belief that open 
architecture programs benefit mass segments of the computer community. 

The ST MUSIC BOX's editor needs to hold much more information than 
the AUTO-PLAYER does. The AUTO-PLAYER's operation is time critical 
so we decided to handle all of the file conversion procedures before the 
player takes over. That is the reason for the slight wait after the editor's 
data loads into the machine. 


/**interf.c*/ 


/* 

** definitions iincluded here 
*/ 


#include 

tinclude 

#include 

tinclude 

tinclude 

tinclude 


<a:portab.h> 
<a:machine.h> 
<a:obdefs.h> 
<a:define.h> 
<a:gemdefs.h> 
<a:osbind.h> 


/* externals here */ 


extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 


int wbox, hbox, durl, dur2, dur3, port_state; 
int dur4,dur5,dur6,dur7,dur8; 

int contrl[12], intin[256], ptsin[256], ptsout[256]; 
int intin[256], intout[256],pxy[10]; 

int newbyte[8], oldbyte[8], typedone, hboxl, wboxl, hcharl; 
int wcharl; 

int l_intin[20], l_out[128], l_ptsin[20]; 

int ev_kreturn,i,iter,gr_mkmx,gr_mkmy, groption,stylem,endm; 
int mode,set_mode; 

int set_font,handle,dummy,gr_mkmstate,gr_mkkstate,prtmem; 
int holdrez,set_effeet; 

int holdx,holdy,whesc,whescl,color_index,colorm,holdclr; 


193 



Abacus Software 


Atari ST MIDI Book 


extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 

extern 


int gr_mkresvd,intstyle,topbot,height,width; 
int exflag,widd,mull,radius; 

int begang,endang,yradius,x_boundary, y_boundary,k,kl,k2,k3,k4; 

int n,u,ab,kk,row,count,column,sp,mod,byte, j,quot,rem,demo; 

int notel, note2, note3, note4, note5, note6, note7, note8; 

int scrold, scrnew, mult, ymult, findex; 

int fcolor, linev, lineh, linesw; 

int bytel, byte2, ig, sgflag,prtsw,path; 

int timex, timey, first, octup; 

int octswO, octswl, octsw2, octsw3, octsw4, octsw5, octsw6; 
int octsw7, meascnt, cnt32; 
int chancnt, progcnt; 

int gfreql, gfreq2, gfreq3, gfreq4,gfreq5, gfreq6,gfreq7,gfreq8; 
int gpsw, gptime, dblol, gvibsw, gprog; 
int st_m; 

long *ptrl, *ptr2, *ptr3, *ptr4, *ptr5, *ptr6, *ptr7, *ptr8; 
char c; 

long logicbase,screenl,screen2,orgscrn,ltemp; 

char bufferl[32767]; /* main display screen */ 

char nbuffl[1024],nbuff2[1024],nbuff3[1024],nbuff4[1024]; 

char nbuff5[1024],nbuff6[1024],nbuff7[1024],nbuff8[1024]; 
char nbuff9[1024],nbuff10[1024],nbuff11[1024],nbuff12[1024]; 

char nbuff13[102 4],nbuff14[102 4], nbuff15[1024],nbuff16[102 4]; 


/* 

** These buffers will hold the music data for the 
** AUTO-PLAYER. The dtab buffers hold note duration 
** data. The ftab buffers hold the frequency values 
** and the vtab buffers are reserved for future use. 
*/ 


extern int dtabl[1024], dtab2[1024],dtab3[1024] , 
dtab4[1024], dtab5[102 4],dtab6[1024] , 
dtab7[1024], dtab8[1024]; 

extern int ftabl[1024], ftab2[1024],ftab3[1024] , 
ftab4[1024], ftab5[102 4],ftab6[102 4] , 
ftab7[1024], ftab8[1024]; 

extern int vtabl[l], vtab2[1],vtab3[1] , 
vtab4[l], vtab5[1],vtab6[1 ] , 
vtab7[1], vtab8[1]; 

extern int ldtmpo[ 264 ]; 


194 



Abacus Software 


Atari ST MIDI Book 


extern int progtab,chanl_buffer[264],chan2_buffer[264]; 
extern int chan3_buffer[264], chan4_buffer[264]; 
extern int portl, port2, port3, port4, vibl, vib2, vib3, vib4; 
extern int xkey; 

extern char tmpo_buffer[ 264 ]; 

/* 

** The progO buffers hold the INSTRUMENT VOICE number. These 
** values are passed to the MIDI synthesizer at the beginning 
** of each measure. 

*/ 

int prog0c[264], proglc[264], prog2c[264], prog3c[264]; 

int fflagl, fflag2, fflag3, fflag4, fflag5, fflag6, fflag7, fflag8; 

/* 

* reserved for future use 

* 

*/ 

showb2 () 

{ 

} 

/* 

** adjust all out of bounds freq vals to rests 
*★ 

** This routine is sort of a broad spectrum anti-biotic 
** routine. There shoud NEVER be any out of bounds values, 

** but we figured if any ever appeared ('the best laid plans... etc 1 ) 
** this routine would clean them up! 

*/ 


ldadjrest () 

{ 

int ldcnt; 

for ( ldcnt = 0/ ldcnt < 1024; ldcnt++ ) 

{ 

if ( ftabl[ ldcnt ] > 96 ) 
ftabl[ ldcnt ] =1; 
if ( ftab2[ ldcnt ] > 96 ) 
ftab2[ ldcnt ] =1; 


195 



Abacus Software 


Atari ST MIDI Book 


if ( ftab3[ ldcnt ] > 96 ) 
ftab3[ ldcnt ] =1; 
if ( ftab4[ ldcnt ] > 96 ) 
ftab4[ ldcnt ] =1; 
if ( ftab5[ ldcnt ] > 96 ) 
ftab5[ ldcnt ] =1; 
if ( ftab6[ ldcnt ] > 96 ) 
ftab6[ ldcnt ] =1/ 
if ( ftab7[ ldcnt ] > 96 ) 
ftab7[ ldcnt ] =1/ 
if ( ftab8[ ldcnt ] > 96 ) 
ftab8[ ldcnt ] =1; 

} 

} 


/* 

* reserved for future use 
*/ 

ttimel () 

{ 

timex = 180; 
timey = 60; 

} 

/* 

** clear the ftab and dtab buffers 
*/ - 


cfdtab () 


{ 


int 

for 


num4 ; 

( num4 = 0; num4 < 1024; num4++ ) 
{ 

ftabl[ num4 ] = 0; 
ftab2[ num4 ] = 0; 
ftab3[ num4 ] = 0; 
ftab4[ num4 ] = 0; 
ftab5[ num4 ] =0; 
ftab6[ num4 ] = 0; 
ftab7[ num4 ] = 0; 
ftab8[ num4 ] = 0; 
dtabl[ num4 ] =0; 
dtab2[ num4 ] = 0; 
dtab3[ num4 ] =0; 
dtab4[ num4 ] =0; 
dtab5[ num4 ] =0; 


196 



Abacus Software 


Atari ST MIDI Book 


dtab6[ num4 ] = 0; 
dtab7[ num4 ] =0; 
dtab8[ num4 ] =0; 

} 

} 

/* 

** adjust duration for tie 
*/ 


adjtie () 

{ 

int tctr; 

for ( tctr = 0; tctr < 1024/ tctr++ ) 

{ 

if ( dtabl [tctr] == 0x65 I I dtabl[tctr] == 0x76 ) 
dtabl[tctr] = 0; 

if ( dtab2 [tctr] == 0x65 || dtab2[tctr] == 0x76 ) 
dtab2[tctr] = 0; 

if ( dtab3 [tctr] == 0x65 || dtab3[tctr] == 0x76 ) 
dtab3[tctr] =0; 

if ( dtab4[tctr] == 0x65 || dtab4[tctr] == 0x76 ) 
dtab4[tctr] = 0; 

if ( dtab5 [tctr] == 0x65 || dtab5[tctr] == 0x76 ) 
dtab5[tctr] = 0; 

if ( dtab6 [tctr ] == 0x65 || dtab6[tctr] == 0x76 ) 
dtab6[tctr] =0; 

if ( dtab7 [tctr] == 0x65 || dtab7 [tctr] == 0x76 ) 
dtab7[tctr] = 0; 

if ( dtab7 [tctr] == 0x65 || dtab8[tctr] == 0x76 ) 
dtab8[tctr] = 0; 

} 

} 

/* 

* sequencer to be called from the editor 


play it () 

{ 

int ldt1, ldt2; 
v__hide_c ( handle ) ; 
holdrez=Getrez(); 

logicbase=Logbase()/ 
orgscrn=Physbase(); 
screenl=(OxffffOO&bufferl); 


/*get monitor rez*/ 

/*get logical base*/ 

/*get scratch screen addr*/ 
/*top screen addr*/ 


197 



Abacus Software 


Atari ST MIDI Book 


ptr2 

ptr3 

ptr4 

ptr5 

ptr6 

ptr7 

ptr8 


/* clear screen */ 

/* print demo grids & text */ 

/* clr dtab and ftab buffers */ 
/* rem— 1 thru 8 here!! */ 


screenl+=(0x100); /*adj ptr*/ 

ptrl = screenl; 

= screenl; 

= screenl; 

= screenl; 

= screenl; 
screenl; 
screenl; 
screenl; 

vsf_perimeter(handle,1); /*edge of shape visible*/ 
Setscreen ( screenl, screenl, -1 ); 
v_clrwk(handle); 
prtdemo(); 
cfdtab(); 
conf 1 () 
conf2 () 
conf3() 
conf4 () 
conf5 () 
conf6 () 
conf7 () 
conf8 () 
clr03 () 
concO() 
concl() 
conc2 () 
conc3() 
ldtrans (); 
ldadjrest (); 
adjtie () ; 
ldgetst (); 
exflag = 0; 
while ( exflag == 

{ 


write Os to prog#c buffs */ 
chan#_buffer -> prog#c */ 


/* trasnspose freq data */ 

/* adjust dur buffers for tie */ 
/* adjust duration buffers */ 

0 ) 


for 


( mod = 0; mod < 1; mod+ + ) /* play once */ 

{ 

first = 0; 

gpsw = 1; /*for demo*/ 

cnt32 =0; 
progcnt = 0; 
measent = st_m; 


chport 

( 1, 

portl, 0 ); /* port 

for 

chan 

# 

0 

*/ 

chport 

( 1, 

port2, 1 ); /* port 

for 

chan 

# 

1 

*/ 

chport 

( 1, 

port3, 2 ); /* port 

for 

chan 

# 

2 

*/ 

chport 

chvib 

( 1, port4, 3 ); /* port 
( vibl, 0 ); /* cc 1 */ 

for 

chan 

# 

3 

*/ 


198 




Abacus Software 


Atari ST MIDI Book 


chvib ( vib2, 1 ); /* cc 1 */ 

chvib ( vib3, 2 )/ /* cc 1 */ 

chvib ( vib4, 3 )/ /* cc 1 */ 

chprog ( 0, prog0c[0] ); /* init program change #1 */ 

chprog ( 1, proglc[0] ); 

chprog ( 2, prog2c[0] ); 

chprog ( 3, prog3c[0] ); 

port_state = Giaccess ( port_state, 0x07 ); 
n = port_state & 0xf8; /*turn on 3 voices*/ 
n |= (0x38); /*no noise here*/ 

Giaccess ( n, 0x87 ); /*set GI sound chip */ 

if ( mod == 0 ) /* set asdr */ 

setenv ( 20000, 20000, 0 ); 

else 

setenv ( 2, 2, 6 ); 
durl = 0; /* set to default */ 

dur2 = 0; 
dur3 =0; 
dur4 =0; 
dur5 = 0; 
dur6 =0; 
dur7 =0; 
dur8 = 0; 
notel =0; 
note2 = 0; 
note3 = 0; 
note4 = 0; 
note5 = 0; 
note6 = 0; 
note7 =0; 
note8 = 0; 

playmusO; /* prelude in c minor */ 


Giaccess( 

0x00, 

0x88 ); 

/* 

off 

snd */ 

Giaccess( 

0x00, 

0x89 ); 

/* 

off 

snd */ 

Giaccess( 

0x00, 

0x8a ); 

/* 

off 

snd */ 

Giaccess 

( port 

state, 0x87 

); 

/* 

restore port */ 


} 

v_clrwk( handle ); 

Setscreen ( orgscrn, orgscrn, -1 ); 

} 


199 



Abacus Software 


Atari ST MIDI Book 


/* 

** turn off all the notes 
★ ★ 

*/ 

for ( ldt2 = 0; ldt2 < 4; ldt2++ ) 

{ 

for ( ldtl = 36; ldtl < 97; ldtl++ ) 

{ 

Bconout ( 3, 128 + ldt2 ); /* chan */ 

Bconout ( 3, ldtl ); /* freq */ 

Bconout ( 3, 0 ); /* vel = 0 = off */ 

} 

} 

} 

/* 

** zero out prog#c buffers 
*/ 

clr03 () 

{ 

int cnt03; 

for ( cnt03 = 0; cnt03 < 264; cnt03++ ) 

{ 

prog0c[ cnt03 ] = 0; 

proglc[ cnt03 ] = 0; 

prog2c[ cnt03 ] = 0; 

prog3c[ cnt03 ] =0; 

} 

} 

/* 

** convert chanl_buffer to progOc buffer 
*/ 

concO () 

{ 

int cnt03, t03; 

if ( chanl_buffer [ 0] == 0 ) /* auto default check */ 
chanl_buffer[0] = 1; 
for ( cnt03 = 0; cnt03 < 264; cnt03++ ) 

{ 

t03 = chanl_buffer[ cnt03 ]; 
if ( t03 != 0 ) 

progOc[ cnt03 ] = t03 - 1; 


200 



Abacus Software 


Atari ST MIDI Book 


else 

{ 

cnt03—; 

t03 = progOc[ cnt03 ]; 
cnt03++; 

progOc[ cnt03 ] = t03; 

} 

} 

} 


/* 

** convert chan2_buffer to proglc buffer 
*/ 

concl () 

{ 

int cnt03, t03; 

if ( chan2_buffer[0] == 0 ) /* auto default check */ 
chan2_buffer[0] = 1; 
for ( cnt03 = 0; cnt03 < 264/ cnt03++ ) 

{ 

t03 = chan2_buffer[ cnt03 ]; 
if ( t03 != 0 ) 

proglc[ cnt03 ] = t03 - 1/ 

else 

{ 

cnt03—; 

t03 = proglc[ cnt03 ]; 
cnt03++; 

proglc[ cnt03 ] = t03; 

} 

} 

} 


/* 

** convert chan3_buffer to prog2c buffer 
*/ 

conc2 () 

{ 

int cnt03, t03; 

if ( chan3_buffer[0] == 0 ) /* auto default check */ 

chan3_buffer[0] = 1; 
for ( cnt03 = 0; cnt03 < 264; cnt03++ ) 


201 



Abacus Software 


Atari ST MIDI Book 


{ 

t03 = chan3_buffer[ cnt03 ]; 
if ( t03 != 0 ) 

prog2c[ cnt03 ] = t03 - 1; 

else 

{ 

cnt03—; 

t03 = prog2c[ cnt03 ]/ 
cnt03++; 

prog2c[ cnt03 ] = t03; 

} 

} 

} 


/* 

** convert chan4_buffer to prog3c buffer 
*/ 

conc3 () 

{ 

int cnt03, t03; 

if ( chan4_buffer [0] == 0 ) /* auto default check */ 
chan4_buffer[0] = 1/ 
for ( cnt03 = 0/ cnt03 < 264/ cnt03++ ) 

{ 

t03 = chan4_buffer[ cnt03 ]; 
if ( t03 != 0 ) 

prog3c[ cnt03 ] = t03 - 1; 

else 

{ 

cnt03—/ 

t03 = prog3c[ cnt03 ]/ 
cnt03++; 

prog3c[ cnt03 ] = t03; 

} 

} 

} 

/* 

** convert tmpo_buffer to ldtmpo buffer 
*/ 

ldgetst() 

{ 


202 



Abacus Software 


Atari ST MIDI Book 


int cnt03, t03; 
int ldxxx[ 264 ]; 
char hcl; 

for ( cnt03 = 0; cnt03 < 264; cnt03++ ) 

{ 

hcl = tmpo_buffer[ cnt03 ]; 

103 = toint ( hcl ); 
ldxxx[ cnt03 ] = t03; 

} 

if ( ldxxx[0] == 0 ) 
ldxxx[0] = 99; 

for ( cnt03 = 0; cnt03 < 264; cnt03++ ) 

{ 

t03 = ldxxx[ cnt03 ]; 
if ( t03 != 0 ) 

ldtmpo[ cnt03 ] = t03; 

else 

{ 

cnt03—; 

t03 = ldtmpo[ cnt03 ]; 
cnt03++; 

ldtmpo[ cnt03 ] = t03; 

} 

} 

} 

/* 

** signed chars need to be converted to integers in alcyon 'C* 
** and therefor this routine - groan! 

*/ 


/* 

* character to integer conversion 
*/ 

toint ( c3 ) 

char c3; 

{ 

char c4; 

int ill; 
ill = 0; 
c4 = 0; 

while ( c3 != c4 ) 


203 



Abacus Software 


Atari ST MIDI Book 


{ 

c4++; 

ill++; 

} 

return ( ill ); 

} 


/* 

* integer to character conversion 
*/ 

tochar ( c3i ) 
int c3i; 

{ 

int c4; 
char ill; 

ill = 0; 
c4 = 0; 

while ( c3i != c4 ) 

{ 

c4++; 

ill++; 

} 

return ( ill ); 

} 

/* 

** Here is a key file conversion routine. The editor uses the 
** values of 49, 55, 66, and 72 to stand for a whole note. 

** The value returned goes into the duration buffer. 

** NOTE: in futute versions of the editor we are planning 
** to change the whole note value to 96 (instead of the 32). 

** All other duration values will also be multiplied by 

** three allowing the use of quarter note and eighth note 

** triplets. 

*/ 

/* 

* integer to duration value 
*/ 


dequ( il7 ) 
int il7; 

{ 

switch ( il7 ) 


204 



Abacus Software 


Atari ST MIDI Book 


{ 

case 49: 
case 55: 
case 66: 
case 72: 

il7 = 32; 
break; 
case 50: 
case 56: 
case 67: 
case 73: 

il7 = 16; 
break; 
case 51: 
case 57: 
case 68: 
case 74: 

il7 - 8; 
break; 
case 52: 
case 58: 
case 69: 
case 75: 

il7 = 4; 
break; 
case 53: 
case 59: 
case 70: 
case 76: 

il7 = 2; 
break; 
case 54: 
case 60: 
case 71: 
case 77: 

il7 = 1; 
break; 
case 100: 
case 117: 

il7 = 100; 
break; 

case 0x65: /* tie fix */ 

case 0x76: 

il7 = 0x65; 
break; 
default: 


205 



Abacus Software 


Atari ST MIDI Book 


il7 = 255; /* bypass sharp and flat */ 

} 

return ( il7 ); 

} 


/* 

* call to convert editor buffs to 

* sequencer buffs 
*/ 

conf1 () 

{ 

char ccl; 
ccl = nbuff2[ 0 ]; 
switch ( ccl ) 

{ 

case 0x00: 

fflagl = 0; 
break; 
default: 

fflagl = 1; 
cvfl () ; 
cvdl(); 
break; 

} 

} 


/* 

** transpose frequency data 
*/ 

ldtrans() 

{ 

int trdum, ctrt, ttt; 

trdum = xkey - 25; /* set value */ 

for ( ctrt = 0; ctrt < 1024; ctrt++ ) 

{ 

if ( ftabl[ ctrt ] >= 2 ) 

{ 

ttt = ftabl[ ctrt ] - trdum; 
if ( ttt <2|| ttt > 96 ) 

ttt = 1; /* forced rest */ 

ftabl[ ctrt ] = ttt; 

} 

if ( ftab2[ ctrt ] >= 2 ) 

{ 


206 



Abacus Software 


Atari ST MIDI Book 


ttt = ftab2[ ctrt ] - trdum; 
if ( ttt <2|| ttt > 96 ) 

ttt = 1; /* forced rest */ 

ftab2[ ctrt ] = ttt; 

} 

if ( ftab3[ ctrt ] >= 2 ) 

{ 

ttt = ftab3[ ctrt ] - trdum; 
if ( ttt <2|| ttt > 96 ) 

ttt = 1; /* forced rest */ 

ftab3[ ctrt ] = ttt; 

} 

if ( ftab4[ ctrt ] >= 2 ) 

{ 

ttt = ftab4[ ctrt ] - trdum; 
if ( ttt <2|| ttt > 96 ) 

ttt = 1; /* forced rest */ 

ftab4[ ctrt ] = ttt; 

} 

if ( ftab5[ ctrt ] >= 2 ) 

{ 

ttt = ftab5[ ctrt ] - trdum; 
if ( ttt <2|| ttt > 96 ) 

ttt = 1; /* forced rest */ 

ftab5[ ctrt ] = ttt; 

} 

if ( ftab6[ ctrt ] >= 2 ) 

{ 

ttt = ftab6[ ctrt ] - trdum; 
if ( ttt <2|| ttt > 96 ) 

ttt = 1; /* forced rest */ 

ftab6[ ctrt ] = ttt; 

} 

if ( ftab7[ ctrt ] >= 2 ) 

{ 

ttt = ftab7[ ctrt ] - trdum; 
if ( ttt <2|| ttt > 96 ) 

ttt = 1; /* forced rest */ 

ftab7[ ctrt ] = ttt; 

} 

if ( ftab8[ ctrt ] >= 2 ) 

{ 

ttt = ftab8[ ctrt ] - trdum; 
if ( ttt <2|| ttt > 96 ) 

ttt = 1; /* forced rest */ 

ftab8[ ctrt ] = ttt; 


207 



Abacus Software 


Atari ST MIDI Book 


} 


} 


} 


/* 

* convert measure freq data 

* to sequencer freq data 
*/ 


cvf1() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill; 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr =0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff2[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 
default: 

nctr = 0; /* element in meas */ 

xflag2 =0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuff2[ mctr + nctr ] ; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1; /* meas done */ 
break; 
default: 

test = toint ( bitter ); 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 

{ 

ftabl[ ctr ] = test; 
nctr++; 


208 



Abacus Software 


Atari ST MIDI Book 


ctr++; 

} 

break; 

} 

} 

} 

mctr += 24; 

} 


/* 

* convert measure freq data 

* to sequencer duration data 
*/ 

cvdl() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill, tempdl; 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr = 0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 

cl = nbuffl[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 
default: 

nctr = 0; /* element in meas */ 

xflag2 = 0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuffl[ mctr + nctr ]; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1; /* meas done */ 
break; 
default: 

tempdl = toint ( bitter ); 
test = dequ ( tempdl ); 
if ( test >= 128 ) 


209 



Abacus Software 


Atari ST MIDI Book 


} 


} 

} 

} 

mctr += 24; 

} 


{ 

nctr++; 

} 

else 

{ 

switch ( test ) 

{ 

case 100: 

case 117: 

ctr—; /* previous */ 

ill=dtabl[ctr]; /*dur*/ 
ctr++; 

dtabl[ctr] = ill/2; 
ctr++; /^restore dur*/ 
nctr++; /*new nbuff*/ 
break; 
default: 

dtabl[ ctr ] = test; 

nctr++; 

ctr++; 

break; 

} 

} 

break; 


/* 

* call to convert editor buffs to 

* sequencer buffs 
*/ 


conf2 () 

{ 

char ccl; 

ccl = nbuff4[ 0 ]; 

switch ( ccl ) 

{ 

case 0x00: 

fflagl = 0; 
break; 
default: 


210 



Abacus Software 


Atari ST MIDI Book 


fflagl = 1; 
cvf2 () ; 
cvd2 () ; 
break; 

} 

} 


/* 

* convert measure freq data 

* to sequencer freq data 
*/ 


cvf2 () 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill; 
xflagl =0; 

ctr = 0; /* ftab element # */ 

mctr = 0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff4[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 
default: 

nctr = 0; /* element in meas */ 

xflag2 = 0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuff4[ mctr + nctr ]; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1; /* meas done */ 
break; 
default: 

test = toint ( bitter ); 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 


211 



Abacus Software 


Atari ST MIDI Book 


{ 

ftab2[ ctr ] = test; 

nctr++; 

ctr++; 

} 

break; 

} 

} 

} 

mctr += 24; 

} 

} 

/* 

* convert measure freq data 

* to sequencer duration data 
*/ 


cvd2() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill, 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr = 0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff3[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 
default: 

nctr = 0; /* element in meas */ 

xflag2 = 0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuff3[ mctr + nctr ]; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1; /* meas done */ 
break; 
default: 


tempdl; 


212 



Abacus Software 


Atari ST MIDI Book 


tempdl = toint ( bitter ); 
test = dequ ( tempdl ); 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 

{ 

switch ( test ) 

{ 

case 100: 

case 117: 

ctr—; /* previous */ 

ill=dtab2[ctr]/ /*dur*/ 
ctr++; 

dtab2[ctr] = ill/2; 
ctr++; /*restore dur*/ 
nctr++; /*new nbuff*/ 
break; 
default: 

dtab2[ ctr ] = test; 

nctr++; 

ctr++; 

break; 

} 

} 

break; 


/* 

* call to convert editor buffs to 

* sequencer buffs 
*/ 


conf3 () 

{ 

char ccl; 

ccl = nbuff6[ 0 ]; 

switch ( ccl ) 

{ 

case 0x00: 


213 



Abacus Software 


Atari ST MIDI Book 


fflagl = 0; 
break; 
default: 

fflagl = 1; 
cvf3(); 
cvd3(); 
break; 

} 

} 

/* 

* convert measure freq data 

* to sequencer freq data 


cvf3() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill; 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr =0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff6[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl =1; 
break; 
default: 

nctr = 0; /* element in meas */ 

xflag2 = 0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuff6[ mctr + nctr ]; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1; /* meas done */ 
break; 
default: 

test = toint ( bitter ); 
if ( test >= 128 ) 

{ 


214 



Abacus Software 


Atari ST MIDI Book 


nctr++; 

} 

else 

{ 

ftab3[ ctr ] = test; 

nctr++; 

ctr++; 

} 

break; 

} 

} 

} 

mctr += 24; 

} 

} 


/* 

* convert measure freq data 

* to sequencer duration data 
*/ 

cvd3() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill, tempdl; 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr = 0; 

mctr = ( st_m - 1 ) *24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff5[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 
default: 

nctr = 0; /* element in meas */ 

xflag2 =0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuff5[ mctr + nctr ]; 
switch ( bitter ) 

{ 

case 0x00: 


215 



Abacus Software 


Atari ST MIDI Book 


xflag2 =1; /* meas done */ 
break; 
default: 

tempdl = toint ( bitter ); 
test = dequ ( tempdl ); 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 

{ 

switch ( test ) 

{ 

case 100: 
case 117: 

ctr—; /* previous */ 

ill=dtab3[ctr]; /*dur*/ 
ctr++; 

dtab3[ctr] = ill/2; 
ctr++; /*restore dur*/ 
nctr++; /*new nbuff*/ 
break; 
default: 

dtab3[ ctr ] = test; 

nctr++; 

ctr++; 

break; 

} 

} 

break; 


/* 

* call to convert editor buffs to 

* sequencer buffs 
*/ 


conf4 () 

{ 

char ccl; 

ccl = nbuff8[ 0 ]; 


216 



Abacus Software 


Atari ST MIDI Book 


switch ( ccl ) 

{ 

case 0x00: 

fflagl = 0; 
break; 
default: 

fflagl - 1; 
cvf 4 () ; 
cvd4(); 
break; 

} 

} 


/* 

* convert measure freq data 

* to sequencer freq data 
*/ 


cvf4() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill; 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr = 0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff8[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 
default: 

nctr = 0; /* element in meas */ 

xflag2 = 0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuff8[ mctr + nctr ]; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 =1; /* meas done */ 
break; 
default: 


217 



Abacus Software 


Atari ST MIDI Book 


> 


test = toint ( bitter ) ; 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 

{ 

ftab4[ ctr ] = test; 

nctr++; 

ctr++; 

} 

break; 

} 

} 

} 

mctr += 24; 

} 


/* 

* convert measure freq data 

* to sequencer duration data 
*/ 

cvd4() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill, tempdl; 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr =0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff7[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 
default: 

nctr = 0; /* element in meas */ 

xflag2 = 0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuff7[ mctr + nctr ]; 


218 



Abacus Software 


Atari ST MIDI Book 


} 


switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1/ /* meas done */ 
break; 
default: 

tempdl = toint ( bitter ); 
test = dequ ( tempdl ); 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 

{ 

switch ( test ) 

{ 

case 100: 
case 117: 

ctr—; /* previous */ 

ill=dtab4[ctr]; /*dur*/ 
ctr++; 

dtab4[ctr] = ill/2; 
ctr++; /*restore dur*/ 
nctr++; /*new nbuff*/ 
break; 
default: 

dtab4[ ctr ] = test; 

nctr++; 

ctr++; 

break; 

} 

} 

break; 

} 

} 

} 

mctr += 24; 

} 


/* 

* call to convert editor buffs to 

* sequencer buffs 
*/ 


219 



Abacus Software 


Atari ST MIDI Book 


conf5 ( ) 

{ 

char ccl; 

ccl = nbuff10 [ 0 ]; 

switch ( ccl ) 

{ 

case 0x00: 

fflagl = 0; 
break; 
default: 

fflagl = 1; 
cvf 5 () ; 
cvd5(); 
break; 

} 

} 


/* 

* convert measure freq data 

* to sequencer freq data 
*/ 

cvf5() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill; 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr = 0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff10[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 
default: 

nctr =0; /* element in meas */ 

xflag2 = 0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuff10[ mctr + nctr ]; 
switch ( bitter ) 

{ 


220 



Abacus Software 


Atari ST MIDI Book 


} 


case 0x00: 

xflag2 = 1/ /* meas done */ 
break; 
default: 

test = toint ( bitter ); 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 

{ 

ftab5[ ctr ] = test; 

nctr++; 

ctr++; 

} 

break; 

} 

} 

} 

mctr += 24; 

} 


/* 

* convert measure freq data 

* to sequencer duration data 
*/ 

cvd5() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill, tempdl; 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr = 0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff9[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 
default: 

nctr = 0; /* element in meas */ 


221 



Abacus Software 


Atari ST MIDI Book 


} 


xflag2 = 0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuff9[ mctr + nctr ]; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1/ /* meas done */ 
break; 
default: 

tempdl = toint ( bitter ); 
test = dequ ( tempdl ); 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 


} 

} 

} 

mctr += 24; 

} 


{ 

switch ( test ) 

{ 

case 100: 

case 117: 

ctr—; /* previous */ 

ill=dtab5[ctr]; /*dur*/ 
ctr++; 

dtab5[ctr] = ill/2; 
ctr++; /*restore dur*/ 
nctr++; /*new nbuff*/ 
break; 
default: 

dtab5[ ctr ] = test; 

nctr++; 

ctr++; 

break; 

} 

} 

break; 


222 



Abacus Software 


Atari ST MIDI Book 


/* 

* call to convert editor buffs to 

* sequencer buffs 
*/ 

conf6() 

{ 

char ccl; 

ccl = nbuff12[ 0 ]; 

switch ( ccl ) 

{ 

case 0x00: 

fflagl = 0; 
break; 
default: 

fflagl = 1; 
cvf 6 () ; 
cvd6(); 
break; 

} 

} 

/* 

* convert measure freq data 

* to sequencer freq data 
*/ 

cvf6() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill; 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr = 0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff12 [ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 
default: 

nctr = 0; /* element in meas */ 

xflag2 = 0; 


223 



Abacus Software 


Atari ST MIDI Book 


> 


while ( xflag2 == 0 ) 

{ 

bitter = nbuff12[ mctr + nctr ] ; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1; /* meas done */ 
break; 
default: 

test = toint ( bitter ); 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 


{ 

ftab6[ ctr ] = test; 

nctr++; 

ctr++; 

} 

break; 

} 

} 

} 

mctr += 24; 

} 


/* 

* convert measure freq data 

* to sequencer duration data 
*/ 


cvd6() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill, 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr = 0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff11[ mctr ]; 
switch ( cl ) 

{ 


tempdl; 


224 



Abacus Software 


Atari ST MIDI Book 


case 0x00: 

xflagl = 1; 
break; 
default: 

nctr =0; /* element in meas */ 

xflag2 = 0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuff11[ mctr + nctr ]; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1; /* meas done */ 
break; 
default: 

tempdl = toint ( bitter ); 
test = dequ ( tempdl ); 
if ( test >= 128 ) 

{ 


nctr++; 

} 

else 

{ 

switch ( test ) 

{ 

case 100: 
case 117: 

ctr—; /* previous */ 

ill=dtab6[ctr]; /*dur*/ 
ctr++; 

dtab6[ctr] = ill/2; 
ctr++; /*restore dur*/ 
nctr++; /*new nbuff*/ 
break; 
default: 

dtab6[ ctr ] = test; 

nctr++; 

ctr++; 

break; 

} 

} 

break; 

} 

} 


} 

mctr += 24; 


225 



Abacus Software 


Atari ST MIDI Book 


} 


} 


/* 

* call to convert editor buffs to 

* sequencer buffs 
*/ 

conf7 () 

{ 

char ccl; 

ccl = nbuff14[ 0 ]; 

switch ( ccl ) 

{ 

case 0x00: 

fflagl = 0; 
break; 
default: 

fflagl = 1; 
cvf 7 () ; 
cvd7(); 
break; 

} 

} 

/* 

* convert measure freq data 

* to sequencer freq data 
*/ 

cvf7 () 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill; 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr = 0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff14[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 


226 



Abacus Software 


Atari ST MIDI Book 


} 


default: 

nctr = 0/ /* element in meas */ 

xflag2 = 0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuffl4[ mctr + nctr ]; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1; /* meas done */ 
break; 
default: 

test = toint ( bitter ); 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 


{ 

ftab7[ ctr ] = test; 

nctr++; 

ctr++; 

} 

break; 

} 

} 

} 

mctr += 24; 


} 


/* 

* convert measure freq data 

* to sequencer duration data 
*/ 

cvd7() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill, tempdl; 
xflagl =0; 

ctr = 0; /* ftab element # */ 

mctr = 0; 

mctr = ( st_m - 1 ) * 24; 
while ( xflagl == 0 ) 

{ 


227 



Abacus Software 


Atari ST MIDI Book 


cl = nbuffl3[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 
default: 

nctr = 0; /* element in meas */ 

xflag2 = 0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuffl3[ mctr + nctr ]; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1; /* meas done */ 
break; 
default: 

tempdl = toint ( bitter ); 
test = dequ ( tempdl ); 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 

{ 

switch ( test ) 

{ 

case 100: 

case 117: 

ctr—; /* previous */ 

ill=dtab7[ctr]; /*dur*/ 
ctr++; 

dtab7[ctr] = ill/2; 
ctr++; /*restore dur*/ 
nctr++; /*new nbuff*/ 
break; 
default: 

dtab7[ ctr ] = test; 

nctr++; 

ctr++; 

break; 

} 

} 

break; 


} 


228 



Abacus Software 


Atari ST MIDI Book 


} 

} 

mctr += 24; 

} 


/* 

* call to convert editor buffs to 

* sequencer buffs 
*/ 

conf8 () 

{ 

char ccl; 

ccl = nbuff16[ 0 ]; 

switch ( ccl ) 

{ 

case 0x00: 

fflagl = 0; 
break; 
default: 

fflagl = 1; 
cvf 8 () ; 
cvd8(); 
break; 

} 

} 

/* 

* convert measure freq data 

* to sequencer freq data 
*/ 

cvf 8() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill; 
xflagl = 0; 

ctr = 0; /* ftab element # */ 

mctr =0; 

mctr = ( st_m - 1 ) *24; 
while ( xflagl == 0 ) 

{ 

cl = nbuff16[ mctr ]; 
switch ( cl ) 

{ 


229 



Abacus Software 


Atari ST MIDI Book 


} 


case 0x00: 

xflagl = 1; 
break; 
default: 

nctr =0; /* element in meas */ 

xflag2 =0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuffl6[ mctr + nctr ]; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1; /* meas done */ 
break; 
default: 

test = toint ( bitter ); 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 


{ 

ftab8[ ctr ] = test; 

nctr++; 

ctr++; 

} 

break; 

} 

} 

} 

mctr += 24; 

} 


/* 

* convert measure freq data 

* to sequencer duration data 
*/ 

cvd8() 

{ 

char bitter, cl; 

int mctr, ctr, nctr, xflagl, xflag2, test, ill, tempdl; 
xflagl =0; 

ctr = 0; /* ftab element # */ 

mctr =0; 


230 



Abacus Software 


Atari ST MIDI Book 


mctr = ( st_m - 1 ) *24; 
while ( xflagl == 0 ) 

{ 

cl = nbuffl5[ mctr ]; 
switch ( cl ) 

{ 

case 0x00: 

xflagl = 1; 
break; 
default: 

nctr = 0; /* element in meas */ 

xflag2 = 0; 

while ( xflag2 == 0 ) 

{ 

bitter = nbuffl5[ mctr + nctr ]; 
switch ( bitter ) 

{ 

case 0x00: 

xflag2 = 1; /* meas done */ 
break; 
default: 

tempdl = toint ( bitter ); 
test = dequ ( tempdl ); 
if ( test >= 128 ) 

{ 

nctr++; 

} 

else 

{ 

switch ( test ) 

{ 

case 100: 

case 117: 

ctr—; /* previous */ 

ill=dtab8[ctr]; /*dur*/ 
ctr++; 

dtab8[ctr] = ill/2; 
ctr++; /*restore dur*/ 
nctr++; /*new nbuff*/ 
break; 
default: 

dtab8[ ctr ] = test; 

nctr++; 

ctr++; 

break; 

} 


231 



Abacus Software 


Atari ST MIDI Book 


} 

break; 

} 

} 

} 

mctr += 24; 

} 


/* 

** end of file interf.c 
*/ 


232 



Abacus Software 


Atari ST MIDI Book 


4.7 movel.c source code 


The routines in this file are used to move animated shapes about the screen. 
Before we present the code to move the shapes, it is important that we 
describe the process used to create shapes. We have defined a grid of 16 
pixels wide by 12 pixels high for the shape. The algorithm which we used 
dictates that there will be one animated shape for each voice that plays. 
When a voice is at rest, the animated shape will disappear. The shape's 
horizontal position on the screen represents the note value. For example, the 
very lowest 'C' note will appear at the left of the display and the very 
highest 'B' note will appear at the far right of the display. If the note 
playing on voice 1 changes from, say middle 'C to 'C#', the shape will 
move ever so slightly to the right. Those of you familiar with the 
PLAYERS and MISSILES from the Atari 130XE will appreciate their 
power. The Atari ST does not have PLAYERS or sprites available for 
programmers. The animation code is very similar to the code presented in 
the ' btdata. c ' file section that writes an icon to the screen. The only 
difference is that the shapes described in the three dimensional array are 
erased, and then re-written at varying positions on the screen. The grid for 
the shapes is two bytes wide and 12 bytes high. Each bit that is on will 
represent a colored pixel being displayed on the screen. Since we want the 
shape to move smoothly about the screen we need 16 different shapes 
which may be drawn to the screen. 


233 



Abacus Software 


Atari ST MIDI Book 


Shape for GRID 

GRID 1 



byte 1 



byte 

2 



row 


bit 



bit 





7 6 5 

4 

3 2 

1 0 

7 6 5 

4 

3 

2 

1 

0 

0 

10 0 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

1 

10 0 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

2 

10 0 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

3 

10 0 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

4 

10 0 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

5 

10 0 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

6 

10 0 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

7 

10 0 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

8 

10 0 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

9 

10 0 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

10 

10 0 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

11 

10 0 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

GRID 2 


byte : 

L 



byte : 

2 





row 

bit 




bit 







7 6 5 

4 

3 2 

1 0 

7 6 5 

4 

3 

2 

1 

0 

0 

0 10 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

1 

0 10 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

2 

0 10 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

3 

0 10 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

4 

0 10 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

5 

0 10 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

6 

0 10 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

7 

0 10 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

8 

0 10 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

9 

0 10 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

10 

0 10 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 

11 

0 10 

0 

0 0 

0 0 

0 0 0 

0 

0 

0 

0 

0 


234 











Abacus Software 


Atari ST MIDI Book 


It is not necessary to show all the grids here because the column of ones 
will continue to move to the right with each of the subsequent grids. The 
animation algorithm of the line moving to the right would be coded with the 
following logic: 

1) Print the bytes for GRID 1 

2) DELAY 

3) Erase GRID 1 

4) Print the bytes for GRID 2 

5) DELAY 

6) erase GRID 2 

7) ...etc... 

Recalling that we are using the medium resolution color mode and taking the 
bit planing arrangement of the Atari ST into consideration, it is clear that we 
need to print 4 bytes across in order to have the line shape appear as black. 
The screen byte arrangement for GRID 1 & 2 would appear as follows. 
Note that the binary number representations have been replaced by their 
decimal counterparts. 


SCREEN BYTE ARRANGEMENTS 


GRID 1 


byte 1 

byte 2 

byte 3 

byte 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 

128 

0 


235 






Abacus Software 


Atari ST MIDI Book 


SCREEN 

BYTE ARRANGEMENTS 


GRID 2 

byte 1 

byte 2 

byte 3 

byte 4 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 

64 

0 


Here is the source to ’movel. c' . 


/* 

** movel.c file 
*/ 

extern int octswO,octswl,octsw2,octsw3,octsw4,octsw5,octsw6,octsw7; 
extern char *ptrl, *ptr2, *ptr3,*ptr4,*ptr5,*ptr6,*ptr7,*ptr8; 

char *newloc, *new21oc, *new31oc,*new41oc, *new51oc,*new61oc,*new71oc; 

char *new81oc; 

extern long screenl; 

/* 

** animate shape tables 
*/ 

char annote[16][12][4] = { 

/* 

** grid 1 
*/ 


236 






Abacus Software 


Atari ST MIDI Book 


128,0,128,0, 
128, 0, 128, 0, 

128,0,128,0, 
128,0,128,0, 
128,0,128,0, 
128,0,128,0, 
128, 0, 128, 0, 

128,0,128,0, 
128,0,128,0, 
128,0,128,0, 
128,0,128,0, 
128,0,128,0, 


/* 

** grid 2 
*/ 

64,0,64,0, 
64,0,64,0, 
64,0,64,0, 
64,0,64,0, 
64,0,64,0, 
64,0,64,0, 
64,0,64,0, 
64,0,64,0, 
64,0,64,0, 
64,0,64,0, 
64,0,64,0, 
64,0,64,0, 


/* 

** grid 3 
*/ 


32,0,32,0, 

32,0,32,0, 

32,0,32,0, 

32,0,32,0, 

32,0,32,0, 

32,0,32,0, 

32,0,32,0, 

32,0,32,0, 

32,0,32,0, 

32,0,32,0, 

32,0,32,0, 

32,0,32,0, 


237 



Abacus Software 


Atari ST MIDI Book 


/* 

** grid 4 
*/ 

16,0,16,0, 
16,0,16,0, 
16,0,16,0, 
16,0,16,0, 
16,0,16,0, 
16,0,16,0, 
16,0,16,0, 
16,0,16,0, 
16,0,16,0, 
16,0,16,0, 
16,0,16,0, 
16,0,16,0, 


/* 

** grid 5 
*/ 

8 , 0 , 8 , 0 , 
8 , 0 , 8 , 0 , 
8 , 0 , 8 , 0 , 
8 , 0 , 8 , 0 , 
8 , 0 , 8 , 0 , 
8 , 0 , 8 , 0 , 
8 , 0 , 8 , 0 , 
8 , 0 , 8 , 0 , 
8 , 0 , 8 , 0 , 
8 , 0 , 8 , 0 , 
8 , 0 , 8 , 0 , 
8 , 0 , 8 , 0 , 


/* 

** grid 6 
*/ 

4,0,4,0, 
4,0,4,0, 
4,0,4,0, 
4,0,4,0, 
4,0,4,0, 
4,0,4,0, 
4,0,4,0, 
4,0,4,0, 
4,0,4,0, 
4,0,4,0, 
4,0,4,0, 
4,0,4,0, 


238 



Abacus Software 


Atari ST MIDI Book 


/* 

** grid 7 
*/ 

2 , 0 , 2 , 0 , 
2 , 0 , 2 , 0 , 
2 , 0 , 2 , 0 , 
2 , 0 , 2 , 0 , 
2 , 0 , 2 , 0 , 
2 , 0 , 2 , 0 , 
2 , 0 , 2 , 0 , 
2 , 0 , 2 , 0 , 
2 , 0 , 2 , 0 , 
2 , 0 , 2 , 0 , 
2 , 0 , 2 , 0 , 
2 , 0 , 2 , 0 , 


/* 

** grid 8 
*/ 

1 , 0 , 1 , 0 , 
1 , 0 , 1 , 0 , 
1 , 0 , 1 , 0 , 
1 / 0 , 1 , 0 , 
1 , 0 , 1 , 0 , 
1 , 0 , 1 , 0 , 
1 , 0 , 1 , 0 , 
1 , 0 , 1 , 0 , 
1 , 0 , 1 , 0 , 
1 , 0 , 1 , 0 , 
1 , 0 , 1 , 0 , 
1 , 0 , 1 , 0 , 


/* 

*★ 

*/ 


grid 9 

0,128,0,128, 
0,128,0,128, 
0,128,0,128, 
0,128,0,128, 
0,128,0,128, 
0,128,0,128, 
0,128,0,128, 
0,128,0,128, 
0,128,0,128, 
0,128,0,128, 
0,128,0,128, 
0,128,0,128, 


239 



Abacus Software 


Atari ST MIDI Book 


/* 


** 

grid 

10 


*/ 





0,64, 

0, 

64, 


0,64, 

0, 

64, 


0,64, 

0, 

64, 


0, 64, 

0, 

64, 


0,64, 

0, 

64, 


0,64, 

o. 

64, 


0,64, 

0, 

64, 


0,64, 

0, 

64, 


0,64, 

0, 

64, 


0,64, 

0, 

64, 


0,64, 

0, 

64, 


0,64, 

0, 

64, 

/* 




** 

grid 

11 


*/ 





0,32, 

0, 

32, 


0,32, 

0, 

32, 


0,32, 

0, 

32, 


0,32, 

0, 

32, 


0,32, 

0, 

32, 


0,32, 

0, 

32, 


0,32, 

0, 

32, 


0,32, 

0, 

32, 


0,32, 

0, 

32, 


0,32, 

0, 

32, 


0,32, 

0, 

32, 


0,32, 

0, 

32, 

/* 




** 

grid 

12 


*/ 





0,16, 

.0, 

16, 


0,16, 

.0, 

16, 


0, 16, 

, 0, 

16, 


0,16, 

-0, 

16, 


0,16, 

.0, 

16, 


0,16, 

.0, 

16, 


0, 16, 

,0, 

16, 


0,16, 

.0, 

16, 


0, 16, 

.0, 

16, 


0,16, 

r 0 , 

16, 


0,16, 

,0, 

16, 


0,16, 

,0, 

16, 


240 



Abacus Software 


Atari ST MIDI Book 


/* 

** grid 13 
*/ 

0 , 8 , 0 , 8 , 
0 , 8 , 0 , 8 , 
0 , 8 , 0 , 8 , 
0 , 8 , 0 , 8 , 
0 , 8 , 0 , 8 , 
0 , 8 , 0 , 8 , 
0 , 8 , 0 , 8 , 
0 , 8 , 0 , 8 , 
0 , 8 , 0 , 8 , 
0 , 8 , 0 , 8 , 
0 , 8 , 0 , 8 , 
0 , 8 , 0 , 8 , 


/* 

** grid 14 
*/ 

0,4,0,4, 
0,4,0,4, 
0,4,0,4, 
0,4,0,4, 
0,4,0,4, 
0,4,0,4, 
0,4,0,4, 
0,4,0,4, 
0,4,0,4, 
0,4,0,4, 
0,4,0,4, 
0,4,0,4, 


/* 

** grid 15 
*/ 

0 , 2 , 0 , 2 , 
0 , 2 , 0 , 2 , 
0 , 2 , 0 , 2 , 
0 , 2 , 0 , 2 , 
0 , 2 , 0 , 2 , 
0 , 2 , 0 , 2 , 
0 , 2 , 0 , 2 , 
0 , 2 , 0 , 2 , 
0 , 2 , 0 , 2 , 
0 , 2 , 0 , 2 , 
0 , 2 , 0 , 2 , 
0 , 2 , 0 , 2 , 


241 



Abacus Software 


Atari ST MIDI Book 


/* 

** grid 16 
*/ 

0,1,0,1, 

0 , 1 , 0 , 1 , 

0 , 1 , 0 , 1 , 

0 , 1 , 0 , 1 , 

0 , 1 , 0 , 1 , 

0 , 1 , 0 , 1 , 

0 , 1 , 0 , 1 , 

0 , 1 , 0 , 1 , 

0 , 1 , 0 , 1 , 

0 , 1 , 0 , 1 , 

0 , 1 , 0 , 1 , 

0 , 1 , 0,1 

} 

/*-move shape as voice 1 moves 0-*/ 

/* 

** This function receives the note #. It will 
** range between 36 to 96. Here is the animation algorithm. 
** 1) take received number and times by 4 

** 2) divide by 16 and store in *quot* 

** 3) remainder goes into ’rem' 

** 4) new screen location goes into 'newloc' 

** 5) ptrl holds OLD location and erases old shape 

** 6) new shape (determined by 'rem' value) 

** The 'rem' value calls the appropriate 

** grid pattern to be stuffed to the screen. 

** 7) ptrl is reset to newest shape position. 

** All the voice animation follows the identical 
** algorithm . 

★ ★ 

*/ 


move11 ( numl ) 
int numl; 

{ 

register int lx, ly; 
int bflag, quot, rem; 

bflag = numl; 
switch ( octswO ) 

{ 

case 0x01: 


242 





Abacus Software 


Atari ST MIDI Book 


numl += 12; 
break; 
case 0x02: 

numl += 24; 
break; 
default: 
break; 

} 

numl *= 4; /* times 2 */ 

quot = numl / 16; 

rem = numl % 16; /* pixel offset */ 

newloc = screenl + ( 4 * quot ); /* byte offset left */ 

for ( ly = 0; ly < 12; ly++ ) /* erase shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*( ptrl + 4 + ( 74 * 160 ) + ( ly * 160 ) + lx ) = 0; 

switch ( bflag ) 

{ 

case 0x01: 

break; 
default: 

for ( ly = 0; ly < 12; ly++ ) /* draw shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*(newloc + 4 + ( 74 * 160 ) + ( ly * 160 ) + lx ) = 

annote[rem][ly][lx]; 

break; 

} 

ptrl = newloc; 

} 


/*-move the right voice 1 shape-*/ 


move21 ( num2 ) 
int num2; 

{ 

register int lx, ly; 
int quot, rem, bflag; 
bflag = num2; 
switch ( octswl ) 

{ 

case 0x01: 

num2 += 12; 
break; 
case 0x02: 

num2 += 24; 


243 





Abacus Software 


Atari ST MIDI Book 


break; 
default: 
break; 

} 

num2 *= 4; /* times 2 */ 

quot = num2 / 16; 

rem = num2 % 16; /* pixel offset */ 

new21oc = screenl + ( 4 * quot ); /* byte offset left */ 

for ( ly = 0; ly < 12; ly++ ) /* erase shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*( ptr2 + 4 + ( 90 * 160 ) + ( ly * 160 ) + lx ) = 0; 

switch ( bflag ) 

{ 

case 0x01: 

break; 
default: 

for ( ly = 0; ly < 12; ly++ ) /* draw shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*(new21oc + 4 + ( 90 * 160 ) + ( ly * 160 ) + lx ) = 
annote[rem][ly][lx]; 

break; 

} 

ptr2 = new21oc; 

} 


/*-move the right voice 3 shape-*/ 


move31 ( num3 ) 
int num3; 

{ 

register int lx, ly; 
int bflag, quot, rem; 
bflag = num3; 
switch ( octsw2 ) 

{ 

case 0x01: 

num3 += 12; 
break; 
case 0x02: 

num3 += 24; 
break; 
default: 
break; 

} 


244 





Abacus Software 


Atari ST MIDI Book 


num3 *= 4; 

quot = num3 / 16; 

rem = num3 % 16; 

new31oc = screenl + ( 4 * quot ); 


/* times 2 */ 

/* pixel offset */ 

/* byte offset left */ 

/* erase shape */ 


for ( ly = 0; ly < 12; ly++ ) 

for ( lx = 0; lx < 4; lx++ ) 

*( ptr3 + 4 + ( 106 * 160 ) + ( ly * 160 ) + lx ) = 0; 


switch ( bflag ) 

{ 

case 0x01: 

break; 
default: 

for ( ly = 0; ly < 12; ly++ ) /* draw shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*(new31oc + 4 + ( 106 * 160 ) + ( ly * 160 ) + lx ) = 
annote[rem][ly][lx]; 

break; 

} 

ptr3 = new31oc; 

} 


/*-move the right voice 4 shape-*/ 


move41 ( num4 ) 
int num4; 

{ 

register int lx, ly; 
int bflag, quot, rem; 
bflag = num4; 
switch ( octsw3 ) 

{ 

case 0x01: 

num4 += 12; 
break; 
case 0x02: 

num4 += 24; 
break; 
default: 
break; 

} 

num4 *= 4; /* times 2 */ 

quot = num4 / 16; 

rem = num4 % 16; /* pixel offset */ 


245 





Abacus Software 


Atari ST MIDI Book 


new41oc = screenl + ( 4 * quot ); /* byte offset left */ 

for ( ly = 0; ly < 12; ly++ ) /* erase shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*( ptr4 + 4 + ( 122 * 160 ) + ( ly * 160 ) + lx ) = 0; 

switch ( bflag ) 

{ 

case 0x01: 

break; 
default: 

for ( ly = 0; ly < 12; ly++ ) 

/* draw shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*<new41oc + 4 + ( 122 * 160 ) + ( ly * 160 ) + lx ) = 
annote[rem][ly][lx]; 

break; 

} 

ptr4 = new41oc; 

} 


/*-move the right voice 5 shape-*/ 


move51 ( num5 ) 
int num5; 

{ 

register int lx, ly; 
int bflag, quot, rem; 
bflag = num5; 
switch ( octsw4 ) 

{ 

case 0x01: 

num5 += 12; 
break; 
case 0x02: 

num5 += 24; 
break; 
default: 
break; 

} 

num5 *= 4; /* times 2 */ 

quot = num5 / 16; 

rem = num5 % 16; /* pixel offset */ 

new51oc = screenl + ( 4 * quot ); /* byte offset left */ 

for ( ly = 0; ly < 12; ly++ ) /* erase shape */ 


246 





Abacus Software 


Atari ST MIDI Book 


for ( lx = 0; lx < 4; lx++ ) 

*( ptr5 + 4 + ( 138 * 160 ) + ( ly * 160 ) + lx ) = 0/ 

switch ( bflag ) 

{ 

case 0x01: 

break; 
default: 

for ( ly = 0; ly < 12; ly++ ) /* draw shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*(new51oc + 4 + ( 138 * 160 ) + ( ly * 160 ) + lx ) = 
annote[rem][ly][lx]; 

break; 

} 

ptr5 = new51oc; 

} 


/*-move the right voice 6 shape-*/ 


move61 ( num6 ) 
int num6; 

{ 

register int lx, ly; 
int bflag, quot, rem; 
bflag = num6; 
switch ( octsw5 ) 

{ 

case 0x01: 

num6 += 12; 
break; 
case 0x02: 

num6 += 24; 
break; 
default: 

break; 

} 

num6 *= 4; /* times 2 */ 

quot = num6 / 16; 

rem = num6 % 16; /* pixel offset */ 

new61oc = screenl + ( 4 * quot ); /* byte offset left */ 

for ( ly = 0; ly < 12; ly++ ) /* erase shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*( ptr6 + 4 + ( 154 * 160 ) + ( ly * 160 ) + lx ) = 0; 

switch ( bflag ) 


247 





Abacus Software 


Atari ST MIDI Book 


{ 

case 0x01: 

break; 
default: 

for ( ly = 0; ly < 12; ly++ ) /* draw shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*(new61oc + 4 + ( 154 * 160 ) + ( ly * 160 ) + lx ) = 
annote[rem][ly][lx]; 

break; 

} 

ptr6 = new61oc; 

} 


/*-move the right voice 7 shape-*/ 


move71 ( num7 ) 
int num7; 

{ 

register int lx, ly; 
int bflag, quot, rem; 
bflag = num7; 
switch ( octsw6 ) 

{ 

case 0x01: 

num7 += 12; 
break; 
case 0x02: 

num7 += 24; 
break; 
default: 
break; 

} 

num7 *= 4; /* times 2 */ 

quot = num7 / 16; 

rem = num7 % 16; /* pixel offset */ 

new71oc = screenl + ( 4 * quot ); /* byte offset left */ 

for ( ly = 0; ly < 12; ly++ ) /* erase shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*( ptr7 + 4 + ( 170 * 160 ) + ( ly * 160 ) + lx ) = 0; 

switch ( bflag ) 

{ 

case 0x01: 

break; 
default: 


248 





Abacus Software 


Atari ST MIDI Book 


for ( ly = 0; ly < 12; ly++ ) /* draw shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*(new71oc + 4 + ( 170 * 160 ) + ( ly * 160 ) + lx ) = 
annote[rem][ly][lx]; 

break; 

} 

ptr7 = new71oc; 

} 


/*-move the right voice 8 shape-*/ 


move81 ( num8 ) 
int num8; 

{ 

register int lx, ly; 
int bflag, quot, rem; 
bflag = num8; 
switch ( octsw7 ) 

{ 

case 0x01: 

num8 += 12; 
break; 
case 0x02: 

num8 += 24; 
break; 
default: 
break; 

} 

num8 *= 4; /* times 2 */ 

quot = num8 / 16; 

rem = num8 % 16; /* pixel offset */ 

new81oc = screenl + ( 4 * quot ); /* byte offset left */ 

for ( ly = 0; ly < 12; ly++ ) /* erase shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*( p tr8 + 4 + ( 186 * 160 ) + ( ly * 160 ) + lx ) = 0; 

switch ( bflag ) 

{ 

case 0x01: 

break; 
default: 

for ( ly = 0; ly < 12; ly++ ) /* draw shape */ 

for ( lx = 0; lx < 4; lx++ ) 

*(new81oc + 4 + ( 186 * 160 ) + ( ly * 160 ) + lx ) = 
annote[rem][ly][lx]; 


249 





Abacus Software 


Atari ST MIDI Book 


break; 

} 

ptr8 = new81oc; 


/* 

** end of movel.c 
*/ 


ST Introduction to MIDI Programing.' 
ST HUolC BOX AUTOPLAYER Filenane 

by Len Dorfnan and.Dennis Young (c) 1986 FUGUE.HUS 
Pressing CONTROL will abort the song and autoload a new one, 


PORTMIEHTO 91 OFF PORTAMENTO RATE OO TEMPO 

CNTRL CD 1 CH 0 OFF CNTRL CD 1 CH 1 OFF 4-1 

CNTRL CD 1 CH 2 OFF CNTRL CD 1 CH 3 OFF 

UOICE 

NUMBER 

HEASURE 

NUMBER 

024 



If 1 

CHAN 81 


it 2 

PR. 810 



it 3 

CHAN 82 


0 4 

PR. 1105 



o 5 

CHAN 83 


it 6 

FR, 813 



8 7 

CHAN 84 


it 8 

PR. 810 


250 







































f— \ 

Appendices 
_!_ ) 























































Abacus Software 


Atari ST MIDI Book 


Compiling The Programs 

The following batch files were used to compile the scaler.c, 
readkey. c and patch. c source code. Rember when using the Acylon 
C compiler that getchar expects a control z to end the input. 

C compiler batch file, C. BAT: 

cp68 %1.c %1.i 

c068 %l.i %1.1 %1.2 %1.3 -f 

rm %1 

cl68 %1.1 %1.2 %l.s 
rm %1.1 
rm %1.2 

as68 -1 -u %l.s 

rm %l.s 

wait 

Link file, LINK1. BAT: 

link68 [u] % 1 .68k=gemstart,%1,vdibind,osbind, aesbind,gemlib,libf 
relmod %1 
rm %1.68k 
wait 

The files eio . c, mdrive . c, sets . c, btdata . c, interf . c and 
movel. c were first compiled using the above C.BAT file, then linked with 
the following file. The first two lines are entered as one complete line. 

Iink68 [u] %1.68k=gemstart,eio,mdrive,sets,btdata, interf,movel,vdibind, 

osbind,aesbind,gemlib,libf 

relmod %1 

rm %1.68k 

wait 


253 



Abacus Software 


Atari ST MIDI Book 


Optional Diskette notes. 


The optional diskette contains the soucrce code and compiled programs for 
all the programs presented in the book. It also includes the following music 
files: 

RAGS.MUS 
WILDR.MUS 
NANETTE.MUS 
MINUET.MUS 
FUGE.MUS 

The optional diskette also includes two version of btdata . c, the one 
presented in the book and one that contains alnemate animation. The main 
focus of the book was MIDI programming and it was not within the scope 
of the book to provide the source for the alternate animation routines. 


254 



Abacus Software 


Atari ST MIDI Book 


Index 


ACTIVE SENSING MESSAGE 

46 

AUTO-PLAYER (ST Music Box) 

7,93-250 

bconin 

57-58 

bconout 

56-58 

BIOS 

56-59 

Bits and bytes 

12,31-35 

btdata.c 

168-192 

bulk dump 

47 

CONTINUE MESSAGE 

46 

channels 

16 

data bytes 

37 

Data format 

36 

DIN cables 

11 

Duration 

4-5,26 

eio. c 

101-118 

EOX MESSAGE 

48 

Extended BIOS 

56-59 

Hexadecimal notation 

53-55 

interf. c 

193-232 

largo 

5 

manufacture’s ID numbers 

49 

mdrive.c 

119-144 

MESSAGE TYPES 

MIDI 

36,46 

beat 

44 

clock 

44 

IMPLEMENTATION 

13-20,23 

implementation chart 

24 

IN/OUT 

3,11 

language 

8,13-20,31-49 

software 

26-28 

SPECIFICATION 1.0 

13-20 


255 



Abacus Software 


Atari ST MIDI Book 


standard 

13 

MODES 

17-18 

move1.c 

233-250 

Note values—see Duration 

OCTAL 

53 

OMINI/POLY 

17 

OMNI ON.MONO 

17 

OMNI OFF/POLY 

17 

patch.c 

77-92 

patches 

19 

Parallel transmission 

12 

Pitch 

6-7 

pitch bend 

16 

Portamento 

4 

RAM cartridge 

21 

readkey.c 

66-76 

Real Time Capture 

27,66 

scaler.c 

58,59-65 

Serial transmission 

12 

set. c 

145-167 

SONG SELECT 

44 

SONG POINTER 

44 

ST MUSIC BOX 

i,7,95-250 

Status bytes 

37 

System exclusive 

37,47 

System real time messages 

45 

System reset message 

46 

Tempo 

5,26 

Vibrato 

16 

wave form 

20 


256 



Optional Diskette 



For your convenience, the 'C' program listings contained in this book are 
available on an SF354 formatted floppy disk. Due to diskette directory 
limitations the BASIC programs were not included. You should order the 
diskette if you want to use the programs, but don't want to type them in 
from the listings in the book. 

All programs on the diskette have been fully tested. You can change the 
programs for your particular needs. The diskette is available for $14.95 plus 
$2.00 ($5.00 foreign) for postage and handling. 

When ordering, please give your name and shipping address. Enclose a 
check, money order or credit card information. Mail your order to: 

Abacus Software 
P.O. Box 7219 
Grand Rapids, MI 49510 


Or for fast service, call 1- 616 / 241-5510. 
















































































































































































P.o. Box 5228 


***** ST MUSIC BOX 

* copyright 1986 



Springfield, Virginia 22150 
(703) 644-8881 
Telex 269728 XLNT UR 

• Compose for ST console speaker or 
MIDI synthesizer 

• Keyboard or mouse entry 

• Smart editor checks beats 
entered per measure 

• All parameter info displayed 
during playback 

• Print high quality sheet music: 

- Add lyrics & other notations 

- Include graphics 

- Print single voice 
or combination 

• Conforms to MIDI 
standard 

• Supports 
monochrome 
and color 


Let the Composer 

in you come out. 


• flexible composing tool: 
- Change key & time signatures 
- Insert, delete copy measures 
- Copy from voice to voice 
- Change instruments measure by 
measure for any voice 
- Alter tempo measure 
by measure 

- Control synthesizer 
portamento 

- Capability to 
transpose notes 

- Load/Save rhythms, 
single voice 

or compositions 

By Dennis Young & Len Dorfman 

Includes four compositions! 




































AA Rated Software 
Atari and Abacus 



A simple-to-use and versatile database 
manager. Features help screens; 
lightning-fast operation; tailorable 
display using multiple fonts; 
user-definable edit masks; capacity up 
to 64,000 records. Supports multiple 
files. RAM-disk support for 1040ST. 
Complete search, sort and file 
subsetting. Interfaces to TextPro. Easy 
printer control. $49.95 



ST TextPro 

Wordprocessor with professional 
features and easy-to-use! Full-screen 
editing with mouse or keyboard 
shortcuts. High speed input, scrolling 
and editing; sideways printing; 
multi-column output; flexible printer 
installation; automatic index and table 
of contents; up to 180 chars/line; 30 
definable function keys; metafile 
output; much more. $49.95 


PaintPro 


JOBL 


Create double¬ 
sized pictures 
£E3l 


PaintPro 


<£2> 


Multiple . 
windows 


For creative illustrations on the ST 


ST PaintPro 

A GEM™ among ST drawing programs. 
Very friendly, but very powerful design 
and painting program. A must for 
everyone's artistic or graphics needs. 
Use up to three windows. You can 
even cut & pa^'e between windows. 
Free-form sketching; lines, circles, 
ellipses, boxes, text, fill, copy, move, 
zoom, spray, paint, erase, undo, help. 
Double-sized picture format. $49.95 



AssemPro 

The complete 68000 
assembler development 
package for the ST 

WMMMWW 


PCBoard 

Designer 

Create printed circuit board layouts 



Auto-routing, component list, pinout list, net list 


ST Forth/MT 

Powerful, multi-tasking Forth for the ST. 
A complete, 32-bit implementation 
based on Forth-83 standard. Develop¬ 
ment aids: full screen editor, monitor, 
macro assembler. 1500+ word library. 
TOS/LINEA commands. Floating point 
and complex arithmetic. $49.95 


ST AssemPro 

Professional developer's package 
includes editor, two-pass interactive 
assembler with error locator, online help 
including instruction address mode and 
GEM parameter information, 
monitor-debugger, disassembler and 
68020 simulator, more. $59.95 


PCBoard Designer 

Interactive, computer aided design 
package that automates layout of printed 
circuit boards. Auto-routlng, 45° or 
90° traces; two-sided boards; pin-to-pin, 
pin-to-BUS or BUS-to-BUS. Rubber¬ 
banding of components during place¬ 
ment. Outputs pinout, component and 
net list. $395.00 


Call now for the name of the dealer nearest you. 
Or order directly using your MC. Visa or Amex 
card. Add $4.00 per order for shipping. Foreign 
orders add $10.00 per item. Call (616) 241-5510 
or write for your free catalog. 30-day money 
back software guarantee. Dealers inquires 
welcome-over 1400 dealers nationwide. 


ST and 1040ST are trademarks of Atari Corp. 
GEM is a trademark of Digital Research Inc. 


Abacus 


immrmi 

mi 

ilium 


P.0. Box 7219 Dept.NB Grand Rapids, Ml 49510 
Phone 616/241-5510 ♦ Telex 709-101 • Fax 616/241-5021 










































































from Abacus 



PRESENTING THE ST 
Gives you an in-depth look at 
this sensational new 
computer. Discusses the 
architecture o< the ST. work¬ 
ing with GEM, the mouse, 
operating system, ail the 
various interlaces, the 68000 
chip and its instructions, 
LOGO. 200pp $16.96 


ST Beginner’s Guide 
Written for the firsthand ST 
user. Get a basic understand¬ 
ing of your ST. Explore 
LOGO and BASIC from the 
ground up. Simple explan¬ 
ations of the hardware and 
internal workings of the ST. 
Illustrations, diagrams. Gloss- 
try. Index. 200pp $14.95 


ST TRICKS & TIPS 
Fantastic collection of pro¬ 
grams and info for the ST. 
Complete programs indude: 
super-fast RAM disk; time¬ 
saving printer spooler; color 
print hardcopy; plotter output 
hardcopy; creating access¬ 
ories. Money saving tricks 
and tips. 260pp $19.95 


ST INTERNALS 
Essential guide to the inside 
information of the ST. 
Detailed descriptions of 
sound and graphics chips, 
internal hardware. I/O ports, 
using GEM. Commented 
BIOS listing. An indispen- 
sible reference for your ST 
library. 45 Opp $19.95 


GEM Programmer's Ref. 
For serious programmers 
needing detailed information 
on GEM. Presented in an 
easy-to-understand format. 
All examples are in C and 
assembly language. Covers 
VDI and AES functions. No 
serious programer should be 
without. 41 Opp $19.95 


MACHINE LANGUAGE 
Program in the fastest lang¬ 
uage for your ATARI ST. 
Learn 68000 assembly lang¬ 
uage, its numbering system, 
use cf registers, structure & 
important details of instruc¬ 
tion set, and use of internal 
system routines. Geared for 
the ST. 280pp $19.95 



ST GRAPHICS A SOUND 
Detailed guide to graphics 
and sound on the ST. 2D & 
3D function plotters, Moirt 
patterns, graphic memory 
and various resolutions, 
fractals, recursion, waveform 
generation. Examples written 
in C. LOGO. BASIC and 
Modda2. 25Opp $19.96 


ST LOGO GUIDE 
Take control of your ST by 
learning ST LOGO—the easy 
to use. powerful language. 
Topics indude: file handling, 
recursion-Hilbert & Sierpinski 
curves. 2D and 3D function 
plots, data structure, error 
handling. Helpful guide for 
ST LOGO users. $19.95 


ST PEEKS A POKES 
Enhance your programs with 
the examples found within 
this book. Explores using 
different languages BASIC, 
C. LOGO and machine 
language, using various 
interfaces, memory usage, 
reading and saving from and 
to disk. more. 280pp $16.96 


BASIC Training Guide 
orough guide for learning 
ST BASIC programming. 
Detailed programming funda¬ 
mentals, commands descrip¬ 
tions, ST graphics & sound, 
using GEM in BASIC, file 
management, disk operation. 
Tutorial problems give hands 
on experience. 300pp $16.95 


BASIC to C 

Move up from BASIC to C. If 
you're already a BASIC 
programmer, you can learn C 
all that much faster. Parallel 
examples demostrate the 
programming techniques and 
constructs in both languages. 
Variables, pointers, arrays, 
data structure. 250pp $19.95 


3D GRAPHICS 
FANTASTICI Rotate, zoom, 
and shade 3D objects. All 
programs written in machine 
language for high speed. 
Learn the mathematics 
behind 3D graphics. Hidden 
line removal, shading. With 
3D pattern maker and 
animator. $24.95 


The ATARI logo and ATARI ST are kademarks of Atari Corp. 


Abacuses Software 


P.0. Box 7219 Dept. A9 Grand Rapids, Ml 49510 - Telex 709-101 • Phone (616) 241-5510 

Optional diskettes are available for all book titles at $14.95 

Call now for the name of your nearest dealer. Or order directly from ABACUS with your MasterCard, VISA, or Amex card. Add 
$4.00 per order for postage and handling. Foreign add $10.00 per book. Other software and books coming soon. Call or 
write for your free catalog. Dealer inquiries welcome-over 1400 dealers nationwide. 







































































































































































- 








Introduction to MIDI Programming 


MIDI -The Musical Instrument Digital Interface. The Atari ST has a 
built-in MIDI interface, which means that it's ready to hook up to any 
digital electronic musical instrument equipped with MIDI ports. The ST 
Introduction to MIDI Programming provides the groundwork for 
discovering the infinite musical possibilities of the Atari ST's MIDI 
interface and your synthesizer. Topics include: 

• Introduction to MIDI programming 

• MIDI STANDARD and MIDI LANGUAGE 

• Programming your synthesizer 

• How to buy a synthesizer 

• How to buy MIDI software 

• Using the extended BIOS 

• The source code from Xlent Software's 
ST MUSIC BOX AUTO-PLAYER program 

• C source codes for a number of programs and functions 

About the authors: 

Len Dorfman and Dennis Young have written a number of best selling 
Atari 8-bit & 16-bit programs for XLent Software. They have combined 
their programming talents and musical knowledge (Len Dorfman plays 
jazz guitar) to introduce you to the MIDI interface of the Atari ST. 


ISBN □-‘Ub43‘i-77-i 


The ATARI logo and ATARI ST are trademarks of Atari Corp. 


you can count on 





ATARI ST INTRO TO MIDI P J?® 0 


11 



232804® 1650 DlW« rTnnt 
POWELL'S 04 COMP - ATARI